如果您想要纯 C 导出,请使用 C 项目而不是 C++。C++ DLL 依赖于所有 C++isms(命名空间等)的名称修饰。您可以通过进入 C/C++->Advanced 下的项目设置将代码编译为 C,有一个选项“编译为”对应于编译器开关 /TP 和 /TC。
如果您仍想使用 C++ 编写 lib 的内部结构,但导出一些未损坏的函数以在 C++ 之外使用,请参阅下面的第二部分。
在 VC++ 中导出/导入 DLL 库
您真正想要做的是在头文件中定义一个条件宏,该宏将包含在您的 DLL 项目的所有源文件中:
#ifdef LIBRARY_EXPORTS
# define LIBRARY_API __declspec(dllexport)
#else
# define LIBRARY_API __declspec(dllimport)
#endif
然后在要导出的函数上使用LIBRARY_API
:
LIBRARY_API int GetCoolInteger();
在您的库构建项目中创建一个定义LIBRARY_EXPORTS
,这将导致为您的 DLL 构建导出您的函数。
由于LIBRARY_EXPORTS
不会在使用 DLL 的项目中定义,因此当该项目包含库的头文件时,将导入所有函数。
如果您的库是跨平台的,您可以在不在 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 是两者中推荐的方法。
从 C++ DLL 中为 LoadLibrary/PInvoke 导出未损坏的函数
如果您需要它来使用 LoadLibrary 和 GetProcAddress,或者可能从另一种语言导入(即来自 .NET 的 PInvoke,或 Python/R 中的 FFI 等),您可以extern "C"
在 dllexport 中使用内联来告诉 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")
);