托管调用非托管下的动态链接库
这里有某个核心的算法是由标准的C++生成的,而网站的服务器要求用ASP.net架构。显然需要在托管环境下调用非托管下的DLL。
其中繁琐的交互微软已经为大家作了很多,我们需要的也就仅仅是在托管环境下添加如下的声明代码:
[DllImport("dll.dll")]
public extern static int f();
这里假设要引用的dll名称为dll.dll,要使用的函数签名为int f()。
下来,需要将dll.dll拷贝到托管程序所在的目录。这样就可以在托管下以任何可以接受的方式使用函数f了。
贸然的行事必将遇到问题:
从上面的输出,证明需要的动态链接库的确是正常的加载了,但没有能在dll.dll中找到一个名字为f的函数。
反查dll.dll头文件,看看签名是否搞错?
#ifdef DLL_EXPORTS
#define DLL_API __declspec(dllexport)
#else
#define DLL_API __declspec(dllimport)
#endif
//…
DLL_API int f(void);
看来我们的签名正确。那问题究竟出在什么地方呢?
想想C++语言本身,它是一个可以支持重载等等语言特征的语言。可不可能是编译器在编译时对f的签名动了手脚呢?
用工具察看dll.dll的导出函数列表,得到如下结果:
其中没有签名类似void f()的出现。看来上面的推测是正确的:C++的编译器会在编译是根据函数参数等的不同对函数名称进行相应的变换。
那现在该如何解决这个问题呢?方向很明确:怎样消除或者避免C++编译器在编译时对函数进行修饰即可。想到C++里有一个extern “C”的语言细节,问题自然会迎刃而解的。只要在导出函数的声明和实现前均加上extern “C”修饰,以上的问题自然就不会再出现了。
#ifdef DLL_EXPORTS
#define DLL_API __declspec(dllexport)
#else
#define DLL_API __declspec(dllimport)
#endif
//声明
extern "C" DLL_API int f(void);
//实现
extern "C" DLL_API int f(void)
{
//....
return 0;
}
用工具再次察看dll.dll的导出函数列表:
可爱的f乖乖的就待在那里,现在再也不用担心找不到它了。
结论:
在制作动态链接库的时候,为了防止编译器对函数名称作不可预料的修饰,需要在导出函数的声明和实现前面同时添加extern “C”选项。
评论