VS COM项目以32位编译,但在尝试编译64位时引发错误C2259

VS COM Project Compiles in 32bit but throws error C2259 when trying to compile 64bit

本文关键字:编译 64位 C2259 错误 项目 COM 32位 VS      更新时间:2023-10-16

你好,我目前正在运行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

测试上下文菜单.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或invoke命令。这个设置的唯一错误是我的原始设置,这是我们所期望的,因为它们没有实现。但是,将配置管理器切换回Win32,您会得到预期的错误,例如3个未解析的外部错误,以及随后命名GetCommandString、InvokeCommand和QueryContextMenu的3个错误。如果它们没有实现,这也是意料之中的事,但为什么x64上的编译器只识别我的原始错误,这是很多人认为的,不是实现的方法,但在win32集上,它显示了未实现时的全部错误。

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

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

您的

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

需要

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

Win32中,不匹配并不那么重要(参数类型解析为同一类型),而在x64中则变得重要。编译器生成输出应该对此给出提示,包括缺少的方法名。