我开发了一个基于C ++ DLL的进程内COM服务器,并使用MinGW + MSYS成功编译了它。如果我使用--enable-stdcall-fixup -Wl,DLLMain.def
开关编译它,那么与COM服务器相关的所有内容都像魅力一样。但是,这样一些符号导出了两次:
'dlltool -z output.def --export-all-symbols libCOMTest.dll'产生:
EXPORTS
...
DeleteCriticalSection@4 @ 14
DllCanUnloadNow @ 15 DATA
DllCanUnloadNow@0 @ 16
DllGetClassObject @ 17 DATA
DllGetClassObject@12 @ 18
DllMain @ 19 DATA
DllMainCRTStartup@12 @ 20
DllRegisterServer @ 21 DATA
DllRegisterServer@0 @ 22
DllUnregisterServer @ 23 DATA
DllUnregisterServer@0 @ 24
EnterCriticalSection@4 @ 25
...
链接器会生成一些警告:
Warning: resolving _DllMain by linking to _DllMain@12
Use --enable-stdcall-fixup to disable these warnings
Use --disable-stdcall-fixup to disable these fixups
Warning: resolving _DllGetClassObject by linking to _DllGetClassObject@12
Warning: resolving _DllCanUnloadNow by linking to _DllCanUnloadNow@0
Warning: resolving _DllRegisterServer by linking to _DllRegisterServer@0
Warning: resolving _DllUnregisterServer by linking to _DllUnregisterServer@0
如果省略这些编译器选项,则DllMain
例程未被导出,因此我甚至无法使用regsvr32
实用程序注册我的COM服务器。
以下是libCOMTest.dll的一些导出符号:
EXPORTS
...
DeleteCriticalSection@4 @ 14
DllCanUnloadNow@0 @ 15
DllGetClassObject@12 @ 16
DllMainCRTStartup@12 @ 17
DllRegisterServer@0 @ 18
DllUnregisterServer@0 @ 19
EnterCriticalSection@4 @ 20
...
如您所见,列表中没有DllMain
例程。
我的.def文件如下所示:
LIBRARY libCOMTest
DESCRIPTION 'libCOMTest in-proc server'
EXPORTS
DllMain @1 PRIVATE
DllGetClassObject @2 PRIVATE
DllCanUnloadNow @3 PRIVATE
DllRegisterServer @4 PRIVATE
DllUnregisterServer @5 PRIVATE
DllMain
例程在没有--enable-stdcall-fixup
编译开关的情况下被取消导出的原因是什么?使用MinGW + MSYS构建进程内COM服务器有什么特殊技巧吗?
汉斯在答案中建议,可以在.def文件中使用重命名语法,如下所示:
EXPORTS
DllGetClassObject = DllGetClassObject@12
DllCanUnloadNow = DllCanUnloadNow@0
DllRegisterServer = DllRegisterServer@0
DllUnregisterServer = DllUnregisterServer@0
guide to building and using Win32 DLLs in Haskell表明一样。
另一种方法是利用--kill-at
链接器开关去除@nn部分:
--kill-at
If given, the stdcall suffixes (@nn) will be stripped from symbols
before they are exported.
答案 0 :(得分:3)
我对您的构建工具了解不多,但可以进行推断。链接器抱怨,因为您要求导出“DllRegisterServer”,但编译器实际上生成了stdcall调用约定所需的标识符“DllRegisterServer @ 0”。这是不匹配的。 --enable-stdcall-fixup选项是一种解决方法,将链接器置于“模糊搜索模式”并允许它找到匹配项。
获得两个导出是草率但实际上不是问题,无论代码使用这些入口点总是要求正确的。绝对不用--export-all-symbols就可以试试。您可以尝试的另一件事是在.def文件中使用重命名语法,不确定您的链接器是否支持它:
DllUnregisterServer=DllUnregisterServer@0 @5 PRIVATE