使用dllexport从DLL中导出函数

我想要一个从C ++窗口DLL中导出函数的简单示例。

我希望看到标题,cpp文件和def文件(如果绝对需要的话)。

我想要导出的名称是undecorated 。 我想使用最标准的调用约定(__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样式的全局函数。

UPDATE

不包括调用约定(和使用extern“C”)给我的出口名称,我喜欢,但这是什么意思? 无论默认调用约定我得到什么pinvoke(.NET),声明(VB6)和GetProcAddress会期望? (我猜GetProcAddress将取决于调用者创build的函数指针)。

我希望这个DLL可以在没有头文件的情况下使用,所以我并不需要很多花哨的#define来使头文件可以被调用者使用。

我很好,答案是我必须使用DEF文件。

如果你想要简单的C导出,使用C项目而不是C ++。 C ++ DLLs依赖于所有C ++ ism(名称空间等)的名称encryption。 通过进入C / C ++ – > Advanced下的项目设置,可以将代码编译为C,编译器开关/ TP和/ TC有一个选项“编译为”。

在VC ++中导出/导入DLL库

你真正想做的是在头文件中定义一个条件macros,这个macros将包含在你的DLL项目的所有源文件中:

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

然后在你想要导出的函数上使用LIBRARY_API

 LIBRARY_API int GetCoolInteger(); 

在你的库构build项目中创build一个定义LIBRARY_EXPORTS这将导致你的函数被导出为你的DLL构build。

由于在使用DLL的项目中不会定义LIBRARY_EXPORTS ,因此当该项目包含库的头文件时,将导入所有的函数。

如果你的图书馆是跨平台的,你可以在没有Windows的情况下将LIBRARY_API定义为“无”:

 #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是两种推荐的方法之一。

从LoadLibrary / PInvoke的C ++ DLL导出unmangled函数

如果你需要这个来使用LoadLibrary和GetProcAddress,或者从.NET中进行PInvoke,你可以在你的dllexport中使用extern "C" 。 而且由于我们使用的是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 

你得到一个符号名称undecorated:

 extern "C" __declspec(dllexport) int Test(void) --> dumpbin : Test 

然而, _stdcall (=macrosWINAPI,改变调用约定)也装饰名称,所以如果我们使用,我们得到:

  extern "C" __declspec(dllexport) int WINAPI Test(void) --> dumpbin : _Test@0 

extern "C"的好处是丢失,因为符号是装饰(_ _bytes)

请注意, 这只发生在x86体系结构上,因为在x64 忽略__stdcall约定( msdn : 在x64体系结构上,按照惯例,参数在可能的情况下传递到寄存器中,随后的参数在堆栈上传递 )。

如果您的目标是x86和x64平台,这是特别棘手的。


两个解决scheme

  1. 使用定义文件。 但这迫使你保持def文件的状态。

  2. 最简单的方法:定义macros(参见msdn ):

#define EXPORT comment(linker,“/ EXPORT:”__FUNCTION__“=”__FUNCDNAME__)

然后在函数体中包含下面的附注:

 #pragma EXPORT 

完整的例子:

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

这将导出x86和x64目标未修饰的函数,同时保留x86的__stdcall约定。 在这种情况下__declspec(dllexport) 不是必需的。

我有完全相同的问题,我的解决scheme是使用模块定义文件(.def)而不是__declspec(dllexport)来定义导出( http://msdn.microsoft.com/en-us/library/d91k01sh.aspx )。 我不知道为什么这个工作,但它确实

我想_naked可能会得到你想要的,但是也会阻止编译器为这个函数生成堆栈pipe理代码。 extern“C”导致C风格的名字装饰。 删除,这应该摆脱你的_。 链接器不会添加下划线,编译器会这样做。 stdcall导致参数堆栈大小被追加。

有关更多信息,请参阅: http : //en.wikipedia.org/wiki/X86_calling_conventions http://www.codeproject.com/KB/cpp/calling_conventions_demystified.aspx

更大的问题是你为什么要这样做? 怎么了?