<span style="font-size:18px;"><span style="font-size:18px;"></span>
<span style="font-size:18px;">
</span>
<span style="font-size:18px;">文件/新建 Win32 Dynamic-Link Library;文件/新建 C++ SourceFile:
_declspec(dllexport) int add(int a,int b){
return a+b;
}
_declspec(dllexport)int subtract(int a,int b){
return a-b;
}
测试文件调用动态链接库中函数的声明:
//_declspec(dllimport) int add(int a,int b);
//_declspec(dllimport) int subtract(int a,int b);
/***********************************************************************************/
通常会给动态链接库提供一个头文件(包含了要导出的函数原型的声明,注释文档):
_declspec(dllimport) int add(int a,int b);
_declspec(dllimport) int subtract(int a,int b);
让调用动态链接库函数的程序添加此头文件。
/***********************************************************************************/
使动态链接库既可给应用程序使用,又可供动态链接库自身使用:
在 .h 头文件中:
#ifdef DLL1_API
#else
#define DLL1_API _declspec(dllimport)
#endif
DLL1_API int add(int a,int b);
DLL1_API int subtract(int a,int b);
在 .cpp 源文件中:
#define DLL1_API __declspec(dllexport) //在动态链接库中定义宏的作用是导出函数
#include "*.h"
int add(int a,int b){
return a+b;
}
int subtract(int a,int b){
return a-b;
}
//在应用程序中不定义宏,就表示导入函数
动态链接库中导出类,在class 后加上宏,类的成员函数都会被导出;
要导出类中的函数,函数定义前加上宏,此时虽然没导出类,但仍可声明类,然后调用导出的函数(public).
/***********************************************************************************/
C++编译器会进行名字改变,若用C编译器就可能导致访问失败:
在定义宏的后面加上 extern "C" // C 必须是大写
#define DLL1_API extern "C" _declspec(dllimport)
// extern "C" 不能导出类的成员函数,只能导出全局函数,不让其发生名字改变
DLL1_API int _stdcall add(int a,int b);
DLL1_API int _stdcall subtract(int a,int b); //标准调用约定,没有_stdcall的是 C调用约定
int _stdcall add(int a,int b){
return a+b;
}
int _stdcall subtract(int a,int b){
return a-b;
}
//若动态链接库给C使用,extern "C";若给C++使用,_stdcall,但这样会使函数名发生改变,cry!
/////////////////////////////////////nothing///////////////////////////////////
可以使用模块定义文件(.def)来解决名字改变问题(laughter):
将def文件添加到动态链接库工程文件中。
.def:
LIBRARY Dll2
EXPORTS
add //链接器发现此名和源文件中函数名相同,就会用add来导出add函数
subtract
源文件只需如此这般:
int add(int a,int b){
return a+b;
}
int subtract(int a,int b){
return a-b;
}
/***********************************************************************************/
动态加载动态链接库(前面都是隐式加载,在链接器选项中输入.lib):
LoadLibrary()
GetProcAdress()
void CDllTestDlg::OnBtnAdd(){
HINSTANCE hInst;
hInst=LoadLibrary("Dll3.dll"); //得到动态链接库模块的句柄
typedef int (/*_stdcall*/ *ADDPROC)(int a,int b); //定义一个函数指针类型
//ADDPROC Add=(ADDPROC)GetProcAddress(hInst,"?add@@YAHHH@Z"); //会发生名字改编
ADDPROC Add=(ADDPROC)GetProcAddress(hInst,MAKEINTRESOURCE(1));//通过函数序号访问(可能出错)
if(!Add){
MessageBox("获取函数地址失败!");
return;
}
CString str;
str.Format("5+3=%d",Add(5,3));
MessageBox(str);
FreeLibrary(hInst); //减少加载的动态链接库的引用计数
}// 动态加载不需头文件,不需lib文件,只需dll即可(把dll文件复制到工程文件中)
当需要访问好多动态链接库时,或只需动态链接库中的少数函数(若隐式把整个动态链接库加载到内存,资源浪费)
适合用动态链接。</span>
<span style="font-size:18px;">
</span>
<span style="font-size:18px;">
</span></span>