这两天被一个DLL的问题困惑了一把,
就是如何编译一个DLL,使之在VC、VB中都能使用。
(下面的描述基于Visual Studio 6.0 sp5,DLL中导出的都是标准C实现的函数)
以前偶在VC中写DLL的函数时都是这样:
假如有一个Extest()函数需要导出,就写
extern "C" __declspec(dllexport) int Extest()
在VC中使用该DLL时,如果需要调用刚才的Extest(),就写
extern "C" __declspec(dllimport) int Extest()
然后在程序中就可以用Extest()了。
这一次,当我在VB的工程中需要调用这个DLL的Extest()时,我先声明:
Declare Function Extest Lib "mydll.dll" () As Integer
然后在程序中调用Extest(),
但是调用完之后总是报一个"Run-time error '49'",
说是"Bad DLL calling convention"。
经过在MSDN中的一通查找,问题已解决,方法如下:
DLL的编写及导出方式
* 在VC中编写DLL的函数这样写:
extern "C" int _stdcall Extest()
* 然后在该工程DEF文件的EXPORTS中加入:Extest
在VC中声明如下,即可使用
extern "C" int _stdcall Extest();
在VB中声明如下,即可使用
Declare Function Extest Lib "mydll.dll" () As Integer
解释两个问题
一、“_stdcall”的作用
在C/C++中函数默认Calling Conventions是:
参数由右向左压入栈,由调用者清空栈。,
在FORTRAN、PASCAL、BASIC等语言中,函数的Calling Conventions是:
参数由右向左压入栈,由被调函数清空栈。
那么在C/C++中使用_stdcall声明函数,
就可以指定C/C++按照FORTRAN等的约定使用函数,
当在FORTRAN等其它语言中调用这些函数就不会出现异常了,
这就是困扰偶的关键了:)
二、加“extern "C"”的作用
extern "C" int _stdcall Extest();
如上的原型,函数名符号会被VC编译器处理为 _Extest@0
int _stdcall Extest();
如上的原型,函数名符号会被VC编译器处理为 ?Extest@@YGXXZ
C语言的编译链接环境不能处理第二种方式的修饰名,所以如果你的DLL
要在C和C++的环境下都适用,那么应该使用第一种命名方式。