Проблема с DllMain в COM внутрипроцессной DLL - PullRequest
1 голос
/ 17 января 2012

Я разработал внутрипроцессорный COM-сервер на основе C ++ DLL и успешно скомпилировал его с MinGW + MSYS.Если я скомпилирую его с --enable-stdcall-fixup -Wl,DLLMain.def, то все, что связано с COM-сервером, работает как шармОднако таким образом некоторые символы экспортируются дважды:

'dlltool -z output.def --export-all-символы 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 не экспортируется, поэтому я даже не могу зарегистрировать свой COM-сервер с помощью утилиты regsvr32.

Ниже приведены некоторые из экспортируемых символов 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 переключателя компиляции?Существуют ли какие-либо специальные приемы для построения внутрипроцессного COM-сервера с MinGW + MSYS?

Решение # 1

Как предложил Ганс в своем ответе, можно использовать синтаксис переименования вфайл .def выглядит следующим образом:

EXPORTS
    DllGetClassObject   = DllGetClassObject@12
    DllCanUnloadNow     = DllCanUnloadNow@0
    DllRegisterServer   = DllRegisterServer@0
    DllUnregisterServer = DllUnregisterServer@0

В руководстве по созданию и использованию DLL-библиотек Win32 в Haskell предлагается то же самое.

Решение # 2

Другой способ - использовать переключатель компоновщика --kill-at для удаления части @nn:

--kill-at
    If given, the stdcall suffixes (@nn) will be stripped from symbols 
    before they are exported. 

1 Ответ

3 голосов
/ 17 января 2012

Я не знаю достаточно о ваших инструментах сборки, но могу экстраполировать. Компоновщик жалуется, потому что вы попросили экспортировать «DllRegisterServer», но компилятор фактически сгенерировал идентификатор «DllRegisterServer @ 0», как требуется для соглашения о вызовах stdcall. Это несоответствие. Для этого можно использовать параметр --enable-stdcall-fixup, который переводит компоновщик в режим нечеткого поиска и позволяет ему найти совпадение.

Получение двух экспортов является неаккуратным, но на самом деле это не проблема, какой бы код ни использовал эти точки входа, всегда будет запрашиваться правильный. Определенно попробуйте это без --export-all-символов. Единственное, что вы можете попробовать, это использовать синтаксис переименования в файле .def, не уверенный, поддерживает ли ваш компоновщик:

        DllUnregisterServer=DllUnregisterServer@0  @5  PRIVATE
...