zoukankan      html  css  js  c++  java
  • c++动态链接库的创建和使用

    动态库

    动态链接库(Dynamic Link Library,DLL)是Windows操作系统中实现共享函数库概念的一种方式,这些库函数的扩展名是 ”.dll”、”.ocx”(包含ActiveX控制的库);

    在使用动态库的时候,往往需要提供两个文件:一个引人库(.lib)和一个DLL文件(.dll);

    1. 引人库(.lib)

      引入库是包含该dll导出的函数和变量的符号名,可以认为是函数和变量的声明;在编译和链接可执行文件时,需要引用引人库中的符号名;

    2. DLL文件(.dll)

      当可执行文件运行并且使用到DLL文件中的函数和变量时,系统才去加载相对应的DLL,并将DLL文件映射到进程的地址空间,然后去访问DLL文件中的导出函数;一句话,dll文件应用于程序运行时。


    创建Win32 DLL文件

    1.创建工程

    在工程中右键添加新项目,项目类型:Win32,模板:Win32项目,输入Dll名字;在弹出的对话框中,选择应用程序类型为“DLL(D)选项”。如下图所示:

    这里写图片描述

    2.添加导出函数

    应用程序如果想要访问某个dll中的函数,那么该函数必须是已经被导出的函数;设置方法如下:

    需要在每一个被导出的函数前面增加标识符:_declspec(dllexport);
    形如:_declspec(dllexport) int add(int a, int b);

    按照指定格式添加其他的导出函数后,点击Build按钮就可以生成.lib文件和.dll文件;我将动态链接库的工程名命名为Sampledll,生成结果位于Ctest解决方案下的Debug目录:

    这里写图片描述


    隐式链接方式加载dll头

    1.函数名字改编问题

    由于C++语言中有函数重载特性,在实际目标文件中函数名会被编译器作特殊处理,比如目标文件的函数名会包含参数类型,而C语言则不会包含参数类型,比如:

    int  add(int a, int b);//代码函数声明
    _add                   //C语言的目标文件函数名
    _add_int_int           //c++语言的目标文件函数名

    为了C语言和C++都能调用dll文件中API函数,我们希望动态链接库文件在编译时,导出函数的名称不要发生变化,为了实现这个目的,在定义导出函数时,需要添加上限定符:extern “C”,C一定要大写

    利用限定符:extern “C”可以解决C++和C语言之间相互调用时函数命名的问题,但是该方法只能用于导出全局函数,不能用于导出一个类的成员函数。

    另外,如果导出函数的调用约定方式发生了变化,即使添加了限定符extern “C”,函数名字在编译dll时还会发生变化。

    2.隐式加载dll方式

    1. 利用extern声明的外部函数,形如:
      extern int _stdcall add(int a, int b);

    2. 利用_declspec(dllimport)声明的外部函数
      _declspec(dllexport) int _stdcall add(int a, int b);

    与extern关键字这种方式相比,使用_declspec(dllimport)标识符声明的外部函数时,它将告诉编译器该函数是从动态链接库中引入的,编译器可以生成运行效率更高的代码。因此,如果调用的函数来自于动态链接库,应该采用_declspec(dllimport)声明外部函数。

    3.头文件设计

    为了方便其他模块引用DLL文件中的API函数,我们在DLL工程中,添加Sampledll.h头文件;其他模块需要使用dll文件中的函数,则先添加Sampledll.h至本工程;
    需要注意的,如果使用这种共享头文件的方式,一定要用_declspec(dllexport)声明的方式,否则没有.lib文件生成。

    头文件内容如下:

    #ifndef _SAMPLE_H_
    #define  _SAMPLE_H_
    
    #ifdef DLL_API
        //内部调用
    #else
        #define DLL_API extern "C" _declspec(dllexport)//外部调用
    #endif
    //接口API
    DLL_API  int _stdcall add(int a, int b);
    DLL_API  int _stdcall  Multiply(int a,int b);
    
    #endif
    

    4.使用动态链接库编程

    我们创建一个MultiThread Win32控制台程序,并在该工程中使用dll文件中的API函数,主要关键步骤如下:
    1. MultiThread工程中添加.lib文件;
    2. 将.lib文件和dll文件放在MultiThread 工程目录下;
    3. #include”Sampledll.h”

    添加.lib文件参考VS2005中添加lib文件的方法文章。

    在MultiThread 工程中,主要关键代码如下:

    stdafx.h

    #pragma once
    
    #include "targetver.h"
    
    #include <stdio.h>
    #include <tchar.h>
    //新增内容,添加lib文件
    #pragma comment(lib, "..\Debug\SampleDll.lib")

    MultiThread .cpp

    #include "..\SampleDll\SampleDll.h"
    
    int _tmain(int argc, _TCHAR* argv[])
    {
        cout << "add      func: " <<      add(2,4) << endl;
        cout << "Multiply func: " << Multiply(2,4) << endl;
     }

    运行结果:

    这里写图片描述


    显示加载方式加载dll

    显示加载dll需要用到以下几个API函数,其函数声明如下:

    //加载dll文件到进行地址空间
    HMODULE WINAPI LoadLibrary(
      __in  LPCTSTR lpFileName
    );
    
    //获取导出函数的地址
    FARPROC WINAPI GetProcAddress(
      __in  HMODULE hModule,
      __in  LPCSTR lpProcName
    );
    
    //释放加载的dll文件
    BOOL WINAPI FreeLibrary(
      __in  HMODULE hModule
    );
    
    //如果有DllMain函数,系统加载dll会调用该函数
    BOOL WINAPI DllMain(
      __in  HINSTANCE hinstDLL,
      __in  DWORD fdwReason,
      __in  LPVOID lpvReserved
    );

    需要注意的是,若dll中的导出函数采用的是标准调用约定时,则访问该dll的客户端程序也应该是采用标准调用约定的导出函数,两者需要一致。

    导通加载dll时,客户端程序不再需要包含导出函数声明的头文件和引入库文件,需要的dll文件即可。

    对于显示加载和隐式链接加载dll的区别如下:

    1. 隐式链接方式加载dll客户端调用简单、便捷;
    2. 在程序启动时,dll文件已经完成加载,并映射到进程的地址空间,可以随时的调用导出函数,没有调用的顺序要求;
    3. 若应用程序需要加载较多的dll文件,则更适用于显示加载dll方式,可以在需要用到某个dll的某个导出函数时,再加载dll,节约程序的启动时间。

    最后,我们想要查看动态链接库导出信息的时,可以使用Dumpbin命令和Depends工具;

  • 相关阅读:
    GC 案例收集整理
    Netty ByteBuf泄露定位修改。
    使用Modernizr 检测HTML5和CSS3浏览器支持功能 (转自http://www.adobe.com/cn/devnet/dreamweaver/articles/using-modernizr.html)
    drupal网站邮件发送功能的实现
    Customizing and Overriding User Login page, Register, and Password Reset in Drupal 6 and 7
    WordPress网站迁移
    HTTP协议详解 (转)
    HTTP协议
    Apache服务器放置多个站点的配置方法 (转)
    Apache禁止或允许固定IP访问特定目录、文件、URL
  • 原文地址:https://www.cnblogs.com/jinxiang1224/p/8468280.html
Copyright © 2011-2022 走看看