I have developed a C++ DLL-based in-proc COM server and successfully compiled it with MinGW + MSYS. If I compile it with --enable-stdcall-fixup -Wl,DLLMain.def switches everything related to COM server works like a charm. However, this way some of the symbols got exported twice:
‘dlltool -z output.def –export-all-symbols libCOMTest.dll’ produces:
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
...
And the linker generates a few warnings:
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
If I omit these compiler options, the DllMain routine got unexported so I can’t even register my COM server with regsvr32 utility.
Below are some of the exported symbols of libCOMTest.dll :
EXPORTS
...
DeleteCriticalSection@4 @ 14
DllCanUnloadNow@0 @ 15
DllGetClassObject@12 @ 16
DllMainCRTStartup@12 @ 17
DllRegisterServer@0 @ 18
DllUnregisterServer@0 @ 19
EnterCriticalSection@4 @ 20
...
As you can see there is no DllMain routine in the list.
My .def file looks as follows:
LIBRARY libCOMTest
DESCRIPTION 'libCOMTest in-proc server'
EXPORTS
DllMain @1 PRIVATE
DllGetClassObject @2 PRIVATE
DllCanUnloadNow @3 PRIVATE
DllRegisterServer @4 PRIVATE
DllUnregisterServer @5 PRIVATE
What is the reason the DllMain routine got unexported without --enable-stdcall-fixup compile switch? Are there any special tricks for building of in-proc COM server with MinGW + MSYS?
The solution #1
As Hans suggested in his answer, it is possible to use the rename syntax in the .def file as follows:
EXPORTS
DllGetClassObject = DllGetClassObject@12
DllCanUnloadNow = DllCanUnloadNow@0
DllRegisterServer = DllRegisterServer@0
DllUnregisterServer = DllUnregisterServer@0
The guide to building and using Win32 DLLs in Haskell suggests just the same.
The solution #2
The other way is to make use of the --kill-at linker switch to strip out @nn part:
--kill-at
If given, the stdcall suffixes (@nn) will be stripped from symbols
before they are exported.
I don’t know enough about your build tools but can extrapolate. The linker is complaining because you asked to export “DllRegisterServer” but the compiler actually generated the identifier “DllRegisterServer@0” as required for the stdcall calling convention. That’s a mismatch. The –enable-stdcall-fixup option is a workaround for that, putting the linker in ‘fuzzy search mode’ and allowing it to find a match.
Getting two exports is sloppy but not actually a problem, whatever code uses these entrypoints is always going to ask for the correct one. Definitely try it without –export-all-symbols. The only other thing you could try is to use the rename syntax in the .def file, not sure if your linker supports it: