一、基本知识
库分为静态库和动态库
动态库的加载则分为隐式链接和显示加载
Dllmain()可有可无
MFC AppWizard(dll)中三种类型中的第一种对应这静态库,第二种则对应则普通的动态库,该动态库不能导出MFC类,但能使用MFC类
第三种相对于第二种来说就是能导出MFC类。
后两者在发布产品时要确保用户机器上有MFC动态链接库。
#pragma comment("dll1.lib")可以代替在project/setings的link选项卡的Object/libarary modules中输入动态库名字
二、只是导出方法的库
1.dll的制作
利用VC++新建一个Win32 Dynamic-Link Library 工程选择空dll项目,然后为该工程添加一个cpp文件并在该文件中加入要导出的函数,最后在各函数前加上:
_declspec(dllexport)
2.调用
在需要调用的地方声明要导入的函数如:
extern int add(int a,int b);
或者用_declspec(dllimport)代替extern
然后在需要用到的地方直接写函数名即可,如int sum=add(3,5);
另外要记得把dll和lib文件拷贝到调用程序的目录下(或者环境变量中),然后在project/setings的link选项卡的Object/libarary modules输入动态库名字,后缀名为.lib。
三、二的改进
可以在制作dll的过程中给使用者提供一个.h文件,在.h文件中,添加如下代码
#ifdef DLL1_API
#else
#define DLL1_API _declspec(dllimport)
#endif
//上面一段主要是区别对待dll中和应用程序中DLL1_API,在dll中,我们在.cpp文件的最开始处定义
//#define DLL1_API _declspec(dllexport),这样当exe和dll的cpp文件在include .h文件时会分别被
//理解为_declspec(dllimport)和_declspec(dllexport)
这样在应用程序中就不用在声明了,只需要include .h文件即可
四、导出一个类及导出一个类中的某个函数
在class 和类名之间加上DLL1_API即可
只是导出一个类中的某个函数则需要把类名前的DLL1_API去掉,并且在要导出的函数前面添加DLL1_API
使用:同使用其他类一样,定义该类的一个变量,然后用该变量调用类成员方法。
五、解决名字改编问题
在_declspec(dllimport)和_declspec(dllexport)前加上extern "C"即可,该方法不适用于导出一个类
而且当调用方式不再是标准的c调用约定,比如是pascal调用预定_stdcall(加在返回类型和函数名之间)时名字改编也是会发生的,利用模块定义文件.def可以解决上面的问题。
六、显示加载dll
例子:
HINSTANCE hInst;
hInst=LoadLibary("Dll1.dll");
typedef int (*ADDPROC)(int a,int b);
ADDPROC add=(ADDPROC)GetProcAddress(hInst,"add");
if(!add)
{
MessageBox("获取函数失败");
return;
}
CString str;
str.Format("%d",add(3,5));
MessageBox(str);
FreeLibary(hInst);//释放,只是在不再需要该函数的地方。
说明:显示加载不需要.lib文件,也不需要在project/setings的link选项卡的Object/libarary modules输入动态库名字.当调用预定改了之后(引起了名字改编)需要修改的地方是在*ADDPROC之前加上调用约定,比如_stdcall(仅typedef这行)
七、根据序号访问导出函数:
GetProcAddress中第二个参数改为MAKEINTRESOURCE(nIndex)即可//nIndex为序号