动态加载动态链接库
使程序在需要时加载动态链接库时加载。尤其是很多动态链接库需要调用时,大大的加快了程序启动的时间。比隐式连接动态链接库更节省内存资源。
首先我们接着重写上次add按钮的代码:
void CDllTestDlg::OnBtnAdd()
{
// TODO: Add your control notification handler code here
//动态加载Dll
HINSTANCE hInst=LoadLibrary("Dll2.dll");
typedef int (*ADDPROC)(int a,int b);
ADDPROC Add=(ADDPROC)GetProcAddress(hInst,"add");
if(!Add)
{
MessageBox("获取函数地址失败!");
return;
}
CString str;
str.Format("5+3=%d,",Add(5,3));
MessageBox(str);
FreeLibrary(hInst);
}
看到这些代码我们首先分析其中的函数:
1,动态加载动态链接库函数:(看到这个函数,我们想到LoadIcon,LoadResource…)
HMODULE LoadLibrary(
LPCTSTR lpFileName // file name of module
);
HMODULE:即模块句柄,这里是实例句柄,MSDN详细,可查阅之。
2.我们这里又定义了一个函数指针类型(*ADDPROC)。用typedef 来定义,ADDPROC来接收GetProcAddress返回的函数地址。
typedef int (*ADDPROC)(int a, int b);
此定义也可看做一个函数,其返回值为int型,且有两个int型的参数。
这里可能有些不懂,那么我们想想:
int add(int a, int b)在存储器中是怎样存储的,我们可以这样假设:
add只是代表一个地址,表示这个函数结构的地址
这个结构中有两个int(4bytes)类型的参数a,b(共占了8bytes)。
那么有人要问了,那返回值呢??
我是这样想的的:函数的参数经过CPU的运算,得到的结果都放进了EAX中,程序要用时只需要把它放到存储器的指定的地址即可。
3.此函数来获取导入函数地址。
FARPROC GetProcAddress(
HMODULE hModule, // handle to DLL module
LPCSTR lpProcName // function name
);
其中FARPROC表示得到指定函数的地址。我们可以用自己定义的ADDPROC来接收此地址。
理解了以上函数,我们基本掌握了动态加载的精华。
为了程序拥有容错的能力。我们判断了ADD是否为空,来处理错误。
这里注意2个问题:
1 当我们把Dll2.dll的调用约定发生变化时,Dll2的导出函数名不发生变化。但是测试程序动态加载时,必须与Dll2.dll中的调用约定保持一致。
int _stdcall add(int a, int b)
{
return a+b;
}
那么:
typedef int (_stdcall *ADDPROC)(int a,int b);
2.
还记得用dumpbin中Dll2.dll导出函数吗??
这里我们可以看到add,subtract分别有一个序号 1, 2。
在GetProcAddress函数中也可以通过导入函数序号来访问函数:
ADDPROC Add=(ADDPROC)GetProcAddress(hInst,MAKEINTRESOURCE(1));
其中MAKEINTRESOURCE宏使一个整形值转变成一个与函数需要相比配资源形式。这里转化成add(即所需要调用的的函数名)。
学习完这些,我们基本上可以编写简单的DLL了。若想精通DLL编写,我们还得继续努力。 http://www.cnblogs.com/fangyukuan/archive/2010/06/21/1761666.html