添加代码。如下:
_declspec(dllimport) int Add(int a, int b); //使用_declspec(dllimport) 声明DLL函数 _declspec(dllimport) int Sub(int a, int b); //注意:是dllimport,不是dllexport _declspec(dllimport) int Sub(int a, int b, bool bIsAbs); void CDllTestDlg::OnBtnAdd() { CString str; str.Format(\ Add(3, 4)); MessageBox(str); }
void CDllTestDlg::OnBtnSub() { CString str; str.Format(\Sub(3, 4)); MessageBox(str); }
void CDllTestDlg::OnBtnAbssub() { CString str; str.Format(\Sub(3, 4, true)); MessageBox(str); }
编译发现,出现LNK2001链接错误。将dll1.lib复制到当前工程目录下,并做如下工程设置:
再次编译将会通过。但运行却又出现错误,提示找不到dll1.dll文件。将dll1.dll也复制到当前工程目录下,再次运行后,一切就正常了。
从上面的编译链接和运行的过程可以知道:dll1.lib文件是链接器进行链接时才需要的,它只是提供了dll1.dll文件中导出函数的函数名等信息,并没有包含实际的函数和数据。函数的实际功能是在程序运行时动态的调用dll1.dll文件时才加载的。也就是说,DLL的调用
者在开发时需要.lib文件,发行时需要.dll文件。
? 也可以不用在工程中进行dll1.lib的设置,在需要调用DLL函数的代码的前面,添加如
下语句:
#pragma comment ( lib, \
这和上图中在工程设置里写上Dll1.lib的效果一样。
? 使用Viaual Studio提供Depends工具可以查看一个EXE文件或者DLL文件在运行时所
依赖的所有动态链接库。如下图所示,说明dlltest.exe文件需要dll1.dll,mfc42d.dll等的支持。
2.2 以extern方式声明外部函数
上面是使用_declspec(dllimport)对外部函数进行的声明,它明确告诉编译器,函数是来自于DLL的,也是较好的声明方式。还有一种extern声明外部函数的方式,将上述dll1.cpp文件的声明中的_declspec(dllimport)替换成extern即可,运行效果也是一样的。如下:
extern int Add(int a, int b); //使用extern声明DLL中的函数 extern int Sub(int a, int b);
extern int Sub(int a, int b, bool bIsAbs);
2.3 使用头文件完善函数的声明,明确告知使用者函数的调用方式。
上面讲过,可以使用DOS命令dumpbin来查看DLL的导出函数有哪些,但dumpbin命令看不到函数的具体参数,返回类型等具体的函数原型。因此,作为DLL的开发者,
有必要提供完整的导出函数的原型,明确告知调用者DLL的用法。
为Dll1工程添加Dll1.h头文件,代码如下:
#ifndef DLL1_API #define DLL1_API _declspec(dllimport) #endif
//int AbsSub(int a, int b) //实际工作中删掉这一行而不是注释掉,隐藏设计创意 DLL1_API int Add(int a, int b); DLL1_API int Sub(int a, int b);
DLL1_API int Sub(int a, int b, bool bAbs);
在Dll1.cpp文件的最前面加上对DLL1_API的定义,如下:
//在此对DLL1_API进行声明,表示当前是导出模式。
//而本DLL的最终使用者不需进行任何声明,默认使用导入模式。 #define DLL1_API _declspec(dllexport)
将Dll1.h文件复制到DllTest工程的目录下,包含进工程的.cpp文件中去,并注释掉原有的_declspec(dllexport)声明。
这样,同一个头文件就可以被开发者和使用者共同使用了。
3、以显式加载的方式使用DLL
这种方式需要调用LoadLibrary()或者类似的函数,来加载动态链接库,再使用GetProcessAddress()获得要调用的每个函数的函数指针,使用完毕后,调用FreeLibrary()卸载DLL。这种方式不需要*.lib文件,也不需要包含*.h文件。但需要知道被调用函数的原型,以便为GetProcessAddress()的返回值定义相应的函数指针。
3.1 建立一个MFC DLL工程MyDll
3.2 在MyDll.cpp文件中 添加函数声明
#include \#ifdef _DEBUG

