第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模块的名称。

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • 一、温故而知新 1. 内存不够怎么办 内存简单分配策略的问题地址空间不隔离内存使用效率低程序运行的地址不确定 关于...
    SeanCST阅读 7,903评论 0 27
  • 原文地址: https://blog.csdn.net/qianchenglenger/article/detai...
    Caiaolun阅读 1,460评论 0 1
  • 原文地址: https://blog.csdn.net/xirongxu_dlut/article/details...
    Caiaolun阅读 8,978评论 0 10
  • 可我等不到晚饭时间了。如果在旅馆,我遇到的情况会更容易解决一些。 最是喜欢这样的感觉,在一般疲累的旅程之后,洗个热...
    深夜芝士阅读 136评论 0 0
  • 大学城环境特别好,婆娑的树影斑驳摇曳,花坛里芬芳馥郁的花随风娉婷,青青的草地生机盎然,阳光懒懒地洒在身上,暖暖...
    笨笨他姐阅读 228评论 0 0