第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 纵观全局

隐式链接方式:

先构建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模块的名称。

你可能感兴趣的:(第19章 DLL基础)