第19章|第19章 DLL基础

19.1 DLL和进程的地址空间
DLL通常由一组可供任何应用程序的独立函数组成。在DLL中通常没有用来处理消息循环或创建窗口的代码。
DLL只不过是一组源代码模块,每个模块包含一些可供应用程序或其他DLL调用的函数。
在应用程序能够调用一个DLL中的函数之前,必须将该DLL的文件映像映射到调用进程的地址空间中。
我们可以通过两种方法来达到这一目的:
1.隐式链接 implicit load-timelinking 默认是加载到内存中的始终占用内存
2.显示链接 explicit run-time linking加载时占用内存,释放了就不占用内存了。如果该DLL已经载入,loadlibrary只是会增加一个引用计数,freelibrary也只是减少引用计数,直到引用计数为0时,DLL才会从内存中移除。
注意:使用.lib就是隐式链接,使用LoadLibrary就是显式链接。
另外,隐式和显式只是对编程的时候来讲的,最后产生的可执行程序,都是用loadlibrary载入的。
两种方法对于你的程序调用动态库时没有任何区别,只是你在编程时,步骤是不一样的。
显式调用麻烦点,但可以没有相应的lib库;隐式调用简单点,有函数的声明就行,但必须有lib库。
在VC中两种方式的具体方法:
一、动态库的隐式调用
在vc工程中直接链接静态输入库xxx.lib,然后即可像调用其它源文件中的函数一样调用DLL中函数。
二、动态库的显式调用
步骤:
1.创建一个函数指针,其指针数据类型要与调用的DLL引出函数相吻合。
2.通过win32 API函数loadlibrary()显示的调用DLL,此函数返回DLL的实例句柄。
3.通过win32 API函数GetProAddress()获取要调用的DLL的函数地址,把结果赋给自定义函数的指针类型。
4.使用函数指针来调用DLL函数。
5.最后调用完成后,通过Win32 API函数FreeLibrary()释放DLL函数。
动态链接库的加载方式:
一、隐式链接
使用lib印入库和相关头文件,dll文件配合使用
二、显式加载
只是使用dll文件即可。
void CDlltextDlg::OnAdd(){
HINSTANCE hnst=LoadLibrary("dll2"); //得到动态链接库的句柄
typedef int (ADDPROC)(int a ,int b); //定义函数指针类型
//用函数指针变量来调用函数int *add(int a, int b)表示函数返回指针值
ADDPROC Add=(ADDPROC)GetProcAddress(hnst, "add"); //得到动态链接库中add导出函数的地址
if(!Add){
MessageBox("获得函数地址失败!");
return;
}
CString str;
str.Format("5+3=%d",Add(5,3));
MessageBox(str);
FreeLibrary(hnst); //释放动态链接库
}
注意:
GetProcAddress也可以采用函数序号方式调用,不过最好是用函数名来获取函数地址
ADDPROC Add=(ADDPROC)GetProcAddress(hnst, MAKEINTRESOURCE(1));
//得到动态链接库中add导出函数的地址,第一个函数表示为add函数


19.2 纵观全局
隐式链接方式:
【第19章|第19章 DLL基础】先构建DLL,在构建可执行模块,因为一个可执行模块需要从另一个DLL模块中导入函数和变量
构建DLL的步骤:
1.创建一个头文件,包含:我们想要在DLL中导出的函数原型/结构以及符号。为了构建该DLL,DLL的所有源文件需要包含这个头文件。
2.创建C++源文件来实现想要在DLL模块中导出的函数和变量。
3.在构建DLL模块时,编译器会对每个源文件进行处理并产生一个.obj模块。
4.当所有.obj模块都创建完毕后,链接器会将所有.obj模块的内容合并起来,产生一个单独的DLL映像文件。该映像文件包含DLL中所有的二进制代码以及全局静态变量。
5.如果链接器检测到DLL的源文件输出了至少一个函数或变量,那么链接器还会生成一个.lib文件。它列出了所有被到处的函数和变量的符号名。
构建可执行模块的步骤:
1.在所有引用了导出的函数/变量/数据结构或符号的源文件中,必须包含由DLL的开发人员所创建的头文件。
2.创建C++源文件来实现想要在DLL模块中导出的函数和变量。当然,代码可以引用在DLL的头文件中定义的函数和变量。
3.在构建可执行模块的时候,编译器会对每个源文件进行处理并产生一个.obj模块。
4.当所有.obj模块都创建完毕后,链接器会将所有.obj模块的内容合并起来,产生一个单独的可执行映像文件。该映像文件包含可执行文件中所有的二进制代码以及全局静态变量。该可执行模块还包含一个导入段(import section),其中列出了所有它需要的DLL模块的名称。

    推荐阅读