【问题标题】:VS COM Project Compiles in 32bit but throws error C2259 when trying to compile 64bitVS COM 项目在 32 位编译,但在尝试编译 64 位时抛出错误 C2259
【发布时间】:2012-07-30 20:48:09
【问题描述】:

您好,我目前正在运行 Visual Studio 2010,并且有一个上下文菜单外壳扩展,它在 32 位机器上完全以 32 位运行,因此所有方法都存在。这是一个 ATL 项目。在 32 位上没有错误甚至警告。

这就是问题所在。当我进入 Visual Studio 下的配置管理器并将活动解决方案平台从 Win32 切换到 x64 并尝试编译时,我收到错误“错误 C2259:'ATL::CCOMObject: 无法实例化抽象类”。

既然这个完全相同的项目确实在 32 位下编译和运行,为什么它会抛出 x64 的错误?

任何想法或正确方向的观点将不胜感激。
需要和实现的主要方法如下:

STDMETHODIMP Initialize(LPCITEMIDLIST, LPDATAOBJECT, HKEY);
STDMETHODIMP GetCommandString(UINT, UINT, UINT*, LPSTR, UINT);
STDMETHODIMP InvokeCommand(LPCMINVOKECOMMANDINFO);
STDMETHODIMP QueryContextMenu(HMENU, UINT, UINT, UINT, UINT);

为了节省代码空间,创建一个 Atl 项目。创建初始项目后,添加一个新类“TestingContextMenu”,其余代码将引用它。

stdafk.h

#include "resource.h"
#include <atlbase.h>
#include <atlcom.h>
#include <atlctl.h>
#include <shlobj.h>
#include <comdef.h>

#include <string>
#include <list>
typedef std::list< std::basic_string<TCHAR> > string_list;

TestingContextMenu.h 仅包含已添加/更改的部分

#include "stdafx.h"
using namespace std;
class ATL_NO_VTABLE CTestingContextMenu:
        public CComObjectRootEx<CComSingleThreadModel>,
    public CComCoClass<CTestingContextMenu, &CLSID_TestingContextMenu>,
    public IShellExtInit,
    public IContextMenu
    {
        // Comment out or remove IDispatch
BEGIN_COM_MAP(CMainMagnimbusContextMenu)
    //COM_INTERFACE_ENTRY(ITestingContextMenu)
    //COM_INTERFACE_ENTRY(IDispatch)
    COM_INTERFACE_ENTRY(IShellExtInit)
    COM_INTERFACE_ENTRY(IContextMenu)
END_COM_MAP()

protected:
    TCHAR m_szFile[MAX_PATH];
    list<string> Filenames;
    list<string> FilenamesCopier;
public:
    STDMETHODIMP Initialize(LPCITEMIDLIST, LPDATAOBJECT, HKEY);

    STDMETHODIMP GetCommandString(UINT, UINT, UINT*, LPSTR, UINT);
    STDMETHODIMP InvokeCommand(LPCMINVOKECOMMANDINFO);
    STDMETHODIMP QueryContextMenu(HMENU, UINT, UINT, UINT, UINT);
};  //There is other code within this but it is autogenerated

TestingContextMenu.cpp

#include "stdafx.h"
#include "TestingContextMenu"
#include <sstream>
using namespace std;
#pragma comment(lib, "comsuppw")

STDMETHODIMP CMainMagnimbusContextMenu::Initialize ( 
  LPCITEMIDLIST pidlFolder,
  LPDATAOBJECT pDataObj,
  HKEY hProgID )
  {
  FORMATETC fmt = { CF_HDROP, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL };
    STGMEDIUM stg = { TYMED_HGLOBAL };
    HDROP     hDrop;

    if ( FAILED( pDataObj->GetData ( &fmt, &stg ) ))
        return E_INVALIDARG;
    hDrop = (HDROP) GlobalLock ( stg.hGlobal );

    UINT uNumFiles = DragQueryFile ( hDrop, 0xFFFFFFFF, NULL, 0 );
   HRESULT hr = S_OK;

   if ( 0 == uNumFiles )
    {
       GlobalUnlock ( stg.hGlobal );
       ReleaseStgMedium ( &stg );
       return E_INVALIDARG;
    }

   UINT counter = 0;
    // Get the name of the every file and store it in our member variable m_szFile.
   for(counter = 0; counter < uNumFiles; counter++)
   {
        if ( 0 == DragQueryFile ( hDrop, counter, m_szFile, MAX_PATH ) )
        {   
            hr = E_INVALIDARG;
        }
        wchar_t* t = _wcsdup(m_szFile);
        char ch[260];
        char DefChar = ' ';
        WideCharToMultiByte(CP_ACP,0,t,-1, ch,260,&DefChar, NULL);
        string ss(ch);
        Filenames.push_back(ss);
        FilenamesCopier.push_back(ss);
   }

   GlobalUnlock ( stg.hGlobal );
   ReleaseStgMedium ( &stg );

   return hr;
}

其余功能可应要求提供。但是我注意到了一些新的东西。如果您刚刚实现了上述功能和代码,并且配置管理器设置为构建 x64,那么您会得到我遇到的初始错误。这甚至意味着不实现 QueryContextMenu、GetCommandString 或调用命令。您在此设置中遇到的唯一错误是我原来的错误,这是我们所期望的,因为它们没有实现。但是,将该配置管理器切换回 Win32,您会得到预期的错误,例如 3 个未解析的外部,以及命名 GetCommandString、InvokeCommand 和 QueryContextMenu 之后的 3 个错误。如果它们未实现,则再次预期,但为什么 x64 上的编译器仅识别我的原始错误,这是很多人认为的,未实现的方法,但在 win32 集上,它在未实现时显示完整错误。

上一段只是我注意到的。我确实正确实现了所有 3 种方法,并且在 Win32 中正确编译,但在 x64 中编译不正确。

【问题讨论】:

  • 错误信息的其余部分是什么?通常有一个未实现成员的列表。否则,请发布一个演示问题的最小重现。
  • 这是整个错误信息。发生在 altcom.h 的这一行 ATLTRY(p = new T1(pv))
  • 在“输出”窗口中查看完整消息,它会告诉您哪个班级成员是麻烦制造者。
  • 感谢查看输出窗口,以下是一个列表,IContextMenu::GetCommandString(): is abstract T1=ATL::CComObject CreateInstance 为什么这与 Win32 到 x64 不同?完全相同的代码可以在 Win32 下正确编译和运行。在配置管理器中设置
  • 专业提示:C++ 编译错误可能很长——在某些情况下可能长达数十或数百行。 Visual Studio 中的错误列表窗口仅显示每个错误、警告和消息的第一行。检查输出窗口总是一个好主意,它将显示编译器的整个输出。大多数情况下,诊断问题只需要第一行,但如果不是,则很有可能输出中可能包含额外的信息。

标签: c++ visual-studio-2010 contextmenu atl shell-extensions


【解决方案1】:

您的GetCommandString 参数与接口方法定义的参数不匹配。

你的

STDMETHODIMP GetCommandString(UINT, UINT, UINT*, LPSTR, UINT)

需要

STDMETHODIMP GetCommandString(UINT_PTR, UINT, UINT*, LPSTR, UINT)

Win32 中,不匹配并不那么重要(参数类型解析为相同的类型),而在x64 中则变得很重要。编译器构建输出应该已经给你一个提示,包括缺少的方法名称。

【讨论】:

  • 这就是问题所在。获取命令字符串未显示该错误。我阅读了 Passants 评论并添加了新信息。尝试了您建议的修复程序并且它有效。编译和程序已经过测试并在 64 位机器上运行。从这些错误中学到了很多关于 c++ 的知识。如果我有代表,我会支持你和帕桑特。
猜你喜欢
  • 1970-01-01
  • 2013-08-25
  • 2019-09-20
  • 2011-05-01
  • 2017-08-03
  • 2011-04-12
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多