Почему я не могу использовать __declspec (dllexport) для экспорта DllGetClassObject () из COM DLL?

Я разрабатываю COM-библиотеку и пытаюсь экспортировать метод DllGetClassObject () с помощью __declspec (dllexport).

Вот моя декларация:

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 ++ принимает STDAPI и extern «C» HRESULT __declspec (dllexport) __stdcall как несовместимые.


person smwikipedia    schedule 11.08.2010    source источник
comment
Вы пробовали просто использовать макросы? Т.е. __declspec(dllexport) STDAPI DllGetClassObject(...);   -  person JSBձոգչ    schedule 11.08.2010
comment
Спасибо за ответ. Я пробовал это. Ошибок компиляции сейчас нет. Но и экспорта нет. Я дважды проверил с помощью DLL Exports Viewer и dumpbin.exe. Это такая дилемма. Это одна из самых неприятных ошибок Microsoft?   -  person smwikipedia    schedule 11.08.2010


Ответы (3)


Я думаю, эта проблема возникает из-за того, что функция __stdcall (для 32-битных сборок) обычно украшена префиксом подчеркивания и постфиксом @count. Но если функция еще помечена как __declspec(dllexport), добавляются дополнительные декорации (__imp, я думаю).

Возможно, вам удастся избежать использования файла .def со следующей прагмой, если вы хотите жить с прагмой (я думаю, что я бы выбрал файл .def):

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

Обратите внимание, что для сборки x64 вам, возможно, придется условно скомпилировать прагму, что, как я думаю, будет:

#pragma comment( linker, "/export:DllGetClassObject" )
person Michael Burr    schedule 11.08.2010
comment
Вот и все ~ Спасибо, Майкл. :) - person smwikipedia; 15.08.2010
comment
@Michael, при этом в DLL будет по 2 экспорта для каждой функции DllGetClassObject и _DllGetClassObject@12 (по крайней мере, это то, что я вижу с помощью Dependency Walker). Есть ли способ экспортировать только DllGetClassObject? - person jyz; 24.07.2013
comment
Обратите внимание, что COM ожидает, что в первую очередь будет экспортировано незапутанное имя (поэтому внутри файла .def не нужно изменять имя). - person Cameron; 23.04.2014

Он не компилируется, потому что исходное объявление в objbase.h не имело атрибута __declspec (dllexport). Вы не можете добавить это в определение. Все равно не поможет, именное украшение неуместно. Майкл показал вам, что с этим делать.

person Hans Passant    schedule 11.08.2010
comment
Спасибо, Ганс. Я очень ценю ваши ответы на мои вопросы. Не только этот. :) - person smwikipedia; 15.08.2010

Я рискну и скажу "да".

Даже Visual Studio 2008 автоматически создает файл .def для проектов .dll ATL COM.

person MSN    schedule 11.08.2010