动态库及测试工程范例:
1. 动态库
1) dll.h内容:
#ifdef DLL_API
#else
#define DLL_API extern "C" _declspec(dllimport)
#endif
DLL_API int Add(int a, int b);
2) dll.cpp内容:
#define DLL_API extern "C" _declspec(dllexport)
#include "Dll.h"
int Add(int a, int b)
{
return a + b;
}
2. 测试工程
静态加载dll方式:
//extern int Add(int a, int b); // 第1中方式
#include "../Dll.h" // 第2种方式
void CTestDllDlg::OnButton1()
{
// TODO: Add your control notification handler code here
CString str;
str.Format("3+5=%d", Add(3, 5));
MessageBox(str);
}
动态加载dll方式:
void CDllTestDlg::OnBtnAdd()
{
// TODO: Add your control notification handler code here
/* CString str;
str.Format("5+3=%d",add(5,3));
MessageBox(str);*/
HINSTANCE hInst;
hInst=LoadLibrary("Dll3.dll");
typedef int (/*_stdcall*/ *ADDPROC)(int a,int b);
//ADDPROC Add=(ADDPROC)GetProcAddress(hInst, "Add");
ADDPROC Add=(ADDPROC)GetProcAddress(hInst,MAKEINTRESOURCE(1));
if(!Add)
{
MessageBox("获取函数地址失败!");
return;
}
CString str;
str.Format("5+3=%d",Add(5,3));
MessageBox(str);
}
extern "C" 是为了解决C++的名字改编问题。但如果函数的调用约定发生了变化,及时在声明导出函数时使用了extern "C",名字改编仍会发生。这时可以使用DEF文件来解决名字改编问题。
并且extern "C" 还有个缺陷就是不能导出类的成员函数,只能导出全局函数这种情况。
这样dll.cpp内容:
int _stdcall Add(int a,int b)
{
return a+b;
}
Dll.def文件内容:
LIBRARY Dll1
EXPORTS
Add
动态库注意事项:
如果提供了DllMain函数,那么此函数中间不要进行太复杂的调用。因为加载该动态库时,可能一些核心动态库还没有被加载,如果DllMain中
的代码需要访问这些动态库中函数就会失败。
2012-01-09补充:
今天做一个C语言的动态库,在C++函数中调用,发现按上面的动态库范例有问题:
1)Dll编译不过,问题出在extern "C",去掉就可以了。
2)在使用动态库的MFC程序中,链接动态库的.lib文件有问题,折腾了好久,也用了def文件的方式,还是有问题。最终在《Windows程序设计》一书中找到答案,所以说,经典就是经典呀。把原因记录一下,供以后参考:
以前参考孙鑫的VC教材,在动态库编程时,有一个用宏定义巧妙的让同一个头文件既能给动态库用,又能给使用动态库的客户程序用的方法,方式就是上面 1.动态库 部分所示。但示例是用C++编写的,没有考虑C的情况,所以在用C编写动态库时,去掉了extern "C"后,对于C++客户程序来说,包含dll的头文件也是没有extern
"C"修饰的,导致链接不上。解决方法是,将头文件改为如下内容,问题解决:
#ifndef _DLL_H_
#define _DLL_H_
#ifdef DLL_API
#else
#ifdef __cplusplus
#define DLL_API extern "C" __declspec (dllimport)
#else
#define DLL_API __declspec (dllimport)
#endif
#endif
DLL_API int Add(int a, int b);
#endif //_DLL_H_
《Windows程序设计》中就是多定义一个宏,秘诀在下面,让我汗颜哪:
#ifdef __cplusplus
#define DLL_API extern "C" __declspec (dllimport)
#else
#define DLL_API __declspec (dllimport)
#endif