使用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
-
使用定义文件。 但这迫使你保持def文件的状态。
-
最简单的方法:定义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
更大的问题是你为什么要这样做? 怎么了?