【问题标题】:Why can't I use __declspec(dllexport) to export DllGetClassObject() from a COM DLL?为什么我不能使用 __declspec(dllexport) 从 COM DLL 导出 DllGetClassObject()?
【发布时间】:2011-03-28 11:52:06
【问题描述】:

我正在开发一个 COM dll 并尝试使用 __declspec(dllexport) 导出 DllGetClassObject() 方法。

这是我的声明:

extern "C" HRESULT __declspec(dllexport) __stdcall DllGetClassObject(REFCLSID rclsid, 
                                                             REFIID riid, void** ppv)

但我一直收到此错误:

error C2375: 'DllGetClassObject' : redefinition; different linkage

所以我尝试检查所有出现的 DllGetClassObject 定义。于是在ObjBase.h中找到了如下一个。

STDAPI  DllGetClassObject(__in REFCLSID rclsid, __in REFIID riid, __deref_out LPVOID FAR* ppv);

STDAPI 原来是这样的:

#define STDAPI                  EXTERN_C HRESULT STDAPICALLTYPE

换句话说,是这样的:

#define STDAPI                  extern "C" HRESULT __stdcall

根据MSDN

要导出函数, __declspec(dllexport) 关键字必须出现在 调用约定关键字,如果是 已指定关键字。

但我之前提到的声明不起作用。

那么 COM DLL 必须def 文件导出它们的方法吗?


更新 1

我用不同的方法名测试了我的声明,如下所示:

extern "C" HRESULT __declspec(dllexport) __stdcall f()
{
    return S_OK;
}

并且此方法已成功导出。所以这些说明符可以一起使用。似乎 Visual C++ 编译器认为 STDAPIextern "C" HRESULT __declspec(dllexport) __stdcall 不兼容。

【问题讨论】:

  • 你试过只使用宏吗? IE。 __declspec(dllexport) STDAPI DllGetClassObject(...);
  • 感谢您的回复。我试过了。现在没有编译错误。但也没有出口。我仔细检查了 DLL Exports Viewer 和 dumpbin.exe。这是一个两难的境地。这是微软最讨厌的错误之一吗?

标签: c++ com name-decoration


【解决方案1】:

我打算出去说是的。

甚至 Visual Studio 2008 也会自动为 ATL COM .dll 项目生成 .def 文件。

【讨论】:

    【解决方案2】:

    我认为出现此问题是因为 __stdcall 函数(用于 32 位构建)通常用下划线前缀和 @count 后缀修饰。但是如果函数也被标记为__declspec(dllexport),则添加额外的装饰(__imp,我认为)。

    如果您愿意接受 pragma,您也许可以避免使用带有以下 pragma 的 .def 文件(我想我会选择 .def 文件):

    #pragma comment( linker, "/export:DllGetClassObject=_DllGetClassObject@12" )
    

    请注意,对于 x64 构建,您可能必须有条件地编译编译指示,我认为应该是:

    #pragma comment( linker, "/export:DllGetClassObject" )
    

    【讨论】:

    • 就是这样~谢谢迈克尔。 :)
    • @Michael,执行此操作后,DLL 将为 DllGetClassObject_DllGetClassObject@12 的每个函数提供 2 个导出(至少我可以通过 Dependency Walker 看到)。有没有办法只导出DllGetClassObject
    • 请注意,COM 期望首先导出一个未修改的名称(因此在 .def 文件中不需要名称修改)。
    【解决方案3】:

    它无法编译,因为 objbase.h 中的原始声明没有 __declspec(dllexport) 属性。您不能将其添加到定义中。无论如何都无济于事,名称装饰不合适。 Michael 向您展示了如何解决这个问题。

    【讨论】:

    • 谢谢汉斯。我非常感谢您对我的问题的回答。不只是这一个。 :)
    猜你喜欢
    • 1970-01-01
    • 2012-04-14
    • 2018-08-05
    • 2021-09-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多