Экспорт функций из библиотеки DLL с помощью dllexport



Я хотел бы простой пример экспорта функции из библиотеки DLL windows C++.



Я хотел бы видеть заголовок, файл cpp и файл Def (если необходимо).



Я бы хотел, чтобы экспортировать имя без отделки. Я хотел бы использовать самое стандартное соглашение о вызовах (__stdcall?). Я бы хотел использовать _ _ declspec (dllexport) и не нужно использовать DEF-файл.



например:



  //header
extern "C"
{
__declspec(dllexport) int __stdcall foo(long bar);
}

//cpp
int __stdcall foo(long bar)
{
return 0;
}


Я пытаясь избежать компоновщик добавил подчеркивания и / или цифры (количество байтов?) к названию.



Я в порядке, не поддерживая dllimport и dllexport, используя один и тот же заголовок. Мне не нужна информация об экспорте методов класса C++, только глобальные функции c-стиля.



обновление



Не включая соглашение о вызовах (и использование extern "C") дает мне имена экспорта, как мне нравится, но что это значит? Является ли любой вызов по умолчанию соглашение я получаю то, что pinvoke (.NET), declare (vb6) и GetProcAddress ожидали бы? (Я предполагаю, что для GetProcAddress это будет зависеть от указателя функции, созданного вызывающим).



Я хочу, чтобы эта DLL использовалась без файла заголовка, поэтому мне действительно не нужно много фантазии #defines, чтобы сделать заголовок доступным для вызывающего абонента.



Я в порядке с ответом, что я должен использовать DEF-файл.

2193   4  

4 ответов:

Если вам нужна обычная экспорта, использовать проект C не c++. Библиотеки DLL C++ полагаются на искажение имен для всех измов C++(пространства имен и т. д...). Вы можете скомпилировать свой код как C, перейдя в настройки вашего проекта в разделе C/C++->Advanced, есть опция "Compile As", которая соответствует переключателям компилятора /TP и /TC.

экспорт / импорт библиотек DLL в VC++

то, что вы действительно хотите сделать, это определить условный макрос в заголовке, которые будут включены в исходные файлы в вашем проекте DLL:

#ifdef LIBRARY_EXPORTS
#    define LIBRARY_API __declspec(dllexport)
#else
#    define LIBRARY_API __declspec(dllimport)
#endif

затем в функции, которую вы хотите экспортировать, вы используете LIBRARY_API:

LIBRARY_API int GetCoolInteger();

в вашей библиотеке построить проект создать define LIBRARY_EXPORTS это приведет к тому, что ваши функции будут экспортированы для вашей сборки DLL.

С LIBRARY_EXPORTS не будет определен в проекте, использующем DLL, когда этот проект включает в себя файл заголовка вашей библиотеки все функции будут импортированы вместо этого.

если ваш библиотека должна быть кросс-платформенной вы можете определить LIBRARY_API как ничто, когда не на Windows:

#ifdef _WIN32
#    ifdef LIBRARY_EXPORTS
#        define LIBRARY_API __declspec(dllexport)
#    else
#        define LIBRARY_API __declspec(dllimport)
#    endif
#elif
#    define LIBRARY_API
#endif

при использовании атрибутом dllexport/атрибута DllImport вам не нужно использовать Def-файлов, если вы используете Def файлы, вам не нужно использовать с атрибутом dllexport/атрибута DllImport. Два метода выполняют одну и ту же задачу по-разному, я считаю, что dllexport/dllimport является рекомендуемым методом из двух.

экспорт несвязанных функций из библиотеки DLL C++ для LoadLibrary / PInvoke

если вы нужно это использовать LoadLibrary и GetProcAddress, или, может быть, делать PInvoke из .NET вы можете использовать extern "C" встроенный в ваш dllexport. И поскольку мы используем GetProcAddress вместо dllimport, нам не нужно выполнять танец ifdef сверху, просто простой dllexport:

Код:

#define EXTERN_DLL_EXPORT extern "C" __declspec(dllexport)

EXTERN_DLL_EXPORT int getEngineVersion() {
  return 1;
}

EXTERN_DLL_EXPORT void registerPlugin(Kernel &K) {
  K.getGraphicsServer().addGraphicsDriver(
    auto_ptr<GraphicsServer::GraphicsDriver>(new OpenGLGraphicsDriver())
  );
}

и вот как выглядит экспорт с помощью Dumpbin / exports:

  Dump of file opengl_plugin.dll

  File Type: DLL

  Section contains the following exports for opengl_plugin.dll

    00000000 characteristics
    49866068 time date stamp Sun Feb 01 19:54:32 2009
        0.00 version
           1 ordinal base
           2 number of functions
           2 number of names

    ordinal hint RVA      name

          1    0 0001110E getEngineVersion = @ILT+265(_getEngineVersion)
          2    1 00011028 registerPlugin = @ILT+35(_registerPlugin)

так этот код отлично работает:

m_hDLL = ::LoadLibrary(T"opengl_plugin.dll");

m_pfnGetEngineVersion = reinterpret_cast<fnGetEngineVersion *>(
  ::GetProcAddress(m_hDLL, "getEngineVersion")
);
m_pfnRegisterPlugin = reinterpret_cast<fnRegisterPlugin *>(
  ::GetProcAddress(m_hDLL, "registerPlugin")
);

Для C++ :

я просто столкнулся с той же проблемой, и я думаю, что стоит упомянуть, что проблема возникает, когда один использует оба __stdcall (или WINAPI)иextern "C":

как известно extern "C" удаляет украшение так, что вместо:

__declspec(dllexport) int Test(void)                        --> dumpbin : ?Test@@YaHXZ

вы получаете имя символа без украшений:

extern "C" __declspec(dllexport) int Test(void)             --> dumpbin : Test
на _stdcall (=макрос WINAPI, который изменяет соглашение о вызове) также украшает имена так что если мы используем оба мы получаем:
   extern "C" __declspec(dllexport) int WINAPI Test(void)   --> dumpbin : _Test@0

и в пользу extern "C" теряется, потому что символ украшен (с _ @байт)

обратите внимание, что это только происходит для архитектуры x86, потому что элемент __stdcall соглашение игнорируется на x64 ( msdn:на архитектурах x64, по соглашению, аргументы передаются в регистры, когда это возможно, и последующие аргументы передаются на стек.).

это особенно сложно, если вы ориентируетесь на платформы x86 и x64.


два решения

  1. используйте файл определения. Но это заставляет Вас поддерживать состояние файла Def.

  2. самый простой способ : определить макрос (см. msdn):

#определить комментарий экспорта (компоновщик, "/ФУНКЦИЯ ЭКСПОРТА=" __" __ FUNCDNAME__)

и затем включите следующую прагму в тело функции:

#pragma EXPORT

Полный Пример :

 int WINAPI Test(void)
{
    #pragma EXPORT
    return 1;
}

это позволит экспортировать функцию без изменений для целей x86 и x64 при сохранении __stdcall Соглашение для x86. Элемент __declspec(dllexport)не требуются в этом случае.

У меня была точно такая же проблема, мое решение было использовать файл определения модуля (.деф) вместо __declspec(dllexport) для определения экспорта(http://msdn.microsoft.com/en-us/library/d91k01sh.aspx). Я понятия не имею, почему это работает, но это делает

Я думаю, что _naked может получить то, что вы хотите, но это также мешает компилятору генерировать код управления стеком для функции. extern "C"вызывает украшение имени стиля C. Удалить, что и что нужно избавиться от _ы. Компоновщик не добавить подчеркивания, компилятор. нарушением соглашения о стандартном приводит аргумент размер стека должен быть добавлен.

дополнительные, видеть: http://en.wikipedia.org/wiki/X86_calling_conventions http://www.codeproject.com/KB/cpp/calling_conventions_demystified.aspx

большой вопрос, почему вы хотите это сделать? Что случилось с искаженными именами?

Comments

    Ничего не найдено.