zoukankan      html  css  js  c++  java
  • 动态链接库DLL

    一、动态链接库(Dynamic Link Library)的生成

    使用动态链接库可以更为容易地将更新应用于各个模块,而不会影响该程序的其他部分。对于一个大型工程,如果把代码都放在一个应用程序exe里,那么日后更新将必须更新整个exe(可能是几Gb),而如果把不同功能的代码分别放在数个动态链接库中,更新只需几个DLL文件。另外,节省内存和代码重用:当多个程序使用同一个函数库时,DLL可以减少在磁盘和物理内存中加载代码的重复量,且有助于代码的重用。

    VC动态链接库的分类:
      Visual C++支持三种DLL,它们分别是Non-MFC DLL(非MFC动态库)、MFC Regular DLL(MFC规则DLL)、MFC Extension DLL(MFC扩展DLL)。

    非MFC动态库不采用MFC类库结构,其导出函数为标准的C接口,能被非MFC或MFC编写的应用程序所调用;MFC规则DLL 包含一个继承自CWinApp的类,但其无消息循环;MFC扩展DLL采用MFC的动态链接版本创建,它只能被用MFC类库所编写的应用程序所调用。

    • non-MFC DLL

    VS2013下,新建一个win32控制台工程,并在应用程序设置窗口中选择“Dll”选项,附加选项选择“空项目”。
    然后 “头文件”右键添加 myDLL.h;“源文件”右键添加 myDLL.cpp

    /////////////////// myDLL.h  ////////////////////////
    #ifndef MYDLL_H_H
    #define MYDLL_H_H
    
    //该宏完成在dll项目内部使用DLL关键字 __declspec(dllexport) 表示导出DLL
    //在dll项目外部使用时,用DLL关键字 __declspec(dllimport) 表示导入DLL  
    //宏DLL_IMPLEMENT在 myDLL.cpp 中定义  
    #ifdef DLL_IMPLEMENT  
    #define DLL_API __declspec(dllexport)  
    #else  
    #define DLL_API __declspec(dllimport)  
    #endif  
    
    #ifdef __cplusplus
    extern "C" {
    #endif
    
    	DLL_API double Add(double a, double b);
    	DLL_API double Subtract(double a, double b);
    
    #ifdef __cplusplus
    }
    #endif
    
    #endif
    
    ///////////////////////// myDLL.cpp  //////////////////////////
    #define DLL_IMPLEMENT 
    #include "myDLL.h"
    
    DLL_API double Add(double a, double b)
    {
    	return a + b;
    }
    DLL_API double Subtract(double a, double b)
    {
    	return a - b;
    }
    

     然后生成(build),就在解决方案 DLL下的Debug中生成五个文件。

    二、使用DLL

    接着在 DLL 解决方案中添加一个项目test,如图

    使用DLL,有两种方式:隐式地调用(静态链接),显示地调用(动态链接)。

    1. 隐式地调用(需要 .h .lib .dll 文件)

    /////////////////// test.cpp  ////////////////////
    
    #include "stdafx.h"
    
    //默认目录为工程目录,即test.vcxproj所在目录
    #include "../myDLL/myDLL.h" 
    #pragma comment(lib, "../Debug/myDLL.lib") //默认目录为工程目录,即test.vcxproj所在目录
    
    //目录结构:  DLL 下包括 myDLL文件夹和 test文件夹	
    //3. 把 myDLL.dll 放在解决方案DLL下的Debug下 或 test 工程的工程目录下。否则出现dll缺失的错误。这个例子,dll与test在同一解决方案下,就不用动了。
    
    int _tmain(int argc, _TCHAR* argv[])
    {
    	double d = Add(3, 5);
    	return 0;
    }
    

     另外,

    .h文件有两种方法引入:

      1. 头文件较少时,直接放在工程目录下,#include "*.h"。若不放工程目录,可以通过相对路径寻找,例如:#include "../myDLL/myDLL.h"

      2. 建立include文件夹,放在里面,然后在项目属性的“c/c++”》“常规”》“附加包含目录”(或“VC++目录”-》“包含目录”),添加include的文件夹的路径,然后程序中 #include "*.h"

    .lib文件有两种方法引入:

      1.lib文件较少时,直接放在工程目录下,#pragma comment(lib, "testCpp.lib");或相对路径

      2.建立lib文件夹,项目的属性页 “链接器”》“常规”》“附加库目录”(“VC++目录”-》“库目录”)添加lib文件夹的路径,然后在项目属性的“链接器”-》“输入”-》“附加依赖项”,添加.lib名字。

      3. 最简单的引入lib的方法:右键属性-》通用属性-》引用-》添加新引用。引入需要的dll工程即可。

    注意:若没有引入lib文件,或引入路径错误,则会出现 “error LNK2019: 无法解析的外部符号” 的错误。


     

    2. 显示地调用DLL

    #include "stdafx.h"
    #include <Windows.h> //for LoadLibrary GetProcAddress
    
    typedef double(*PFUNC) (double, double);//定义函数指针类型PFUNC
    int _tmain(int argc, _TCHAR* argv[])
    {
    	PFUNC add, sub;
    	//1.加载DLL。LoadLibrary()
    	//dll文件要放在test工程目录或test.exe所在目录(即DLL下的Debug目录)。
    	//如果生成的EXE文件要直接运行,则要保证EXE文件与DLL文件在同一目录下。
    	HMODULE h = ::LoadLibrary(_T("myDLL.dll"));
    	//2.获取函数地址。GetProcAddress()
    	//“Add”是DLL中的函数符号。若要函数符号与函数名相同,
    	//需要在dll的头文件中函数声明前加 extern "C",或者在dll工程中写模块定义 .def 文件
    	add = (PFUNC)::GetProcAddress(h, "Add");
    	double d = add(3, 5);//或 double d = (*add)(3,5);
    	//double sd = sub(9, 8.5);
    	// 3.释放资源
    	::FreeLibrary(h);
    	return 0;
    }
    

    在win32下, HINSTANCE == HMODULE  实际上是一个 无符号长整数。

    在要输出的函数、类、数据的声明前加上_declspec(dllexport)的修饰符,表示输出。__declspec (dllexport)在C调用约定、C编译情况下可以去掉输出函数名的下划线前缀。

     

    开始->所有程序->Microsoft Visual Studio 2010->Visual Studio Tools ->“Visual Studio 命令提示(2010)”后,

    就像普通的cmd一样的命令行环境,就可以正常使用VS的一些工具,其中就包括dumpbin。输入如下命令,查看dll信息:

    D:Program Files (x86)Microsoft Visual Studio 10.0VC>dumpbin -exports D:WorkSpaceDLLTutorialDebugDLLTutorial.dll

    测试 myDLL.dll,当没有加 extern "C" 时:

    当加 extern ”C"时:

    以上两种情况都有 __declspec(dllexport) 。当没有 __declspec(dllexport)  的情况时,...

    使用 .def 文件

    .def文件的规则为:

     (1)LIBRARY语句说明.def文件相应的DLL;

     (2)EXPORTS语句后列出要导出函数的名称。可以在.def文件中的导出函数名后加@n,表示要导出函数的序号为n  (在进行函数调用时,这个序号将发挥其作用);

     (3).def 文件中的注释由每个注释行开始处的分号 (;) 指定,且注释不能与语句共享一行。

    ;DLL库的 .def文件
    LIBRARY myDLL
    EXPORTS
    Add @ 1
    Subtract @ 2
    

    DLL参考:
    www.cnblogs.com/qinguoyi/p/7257353.html
    www.cnblogs.com/whiteyun/archive/2011/07/22/2113668.html (重要)
    www.cnblogs.com/woshitianma/p/3681745.html(重要)
    www.cnblogs.com/azbane/p/7492820.html
    www.cnblogs.com/lidabo/p/7121745.html
    www.cnblogs.com/code1992/p/9585853.html (重要)https://pcedu.pconline.com.cn/empolder/gj/vc/0509/698632_all.html
    DLL导出类:blog.csdn.net/liubing8609/article/details/82156067
    extern "C" 的知识参考:www.cppblog.com/FateNo13/archive/2009/08/03/92052.html


    MFC 扩展 DLL

    新建的 MFC扩展DLL的工程后,默认有 _AFXEXT 的宏定义。(可以 工程属性》C/C++》预处理器》预处理器定义   查看)
    故可直接在 类名 前加 AFX_EXT_CLASS 来导出类。

    导出类的时候直接用这个AFX_EXT_CLASS 就ok了
    class AFX_EXT_CLASS CMyDlg : public CDialogEx
    {
    DECLARE_DYNAMIC(CMyDlg)
    public:
    CMyDlg(CWnd* pParent = NULL);   // 标准构造函数
    virtual ~CMyDlg();
    // 对话框数据
    enum { IDD = IDD_MYDLG };
    protected:
    virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV 支持
    DECLARE_MESSAGE_MAP()
    };
    然后在工程属性- c/c++  - 预处理器 - 预处理器定义  添加   _AFXEXT; WIN32;_WINDOWS;_DEBUG;
    进去看宏,发现都已经帮我们做好了,当然你喜欢也可以自己去定义 __declspec(dllexport)

    #ifndef AFX_EXT_DATA
    #ifdef _AFXEXT
    #define AFX_EXT_CLASS       AFX_CLASS_EXPORT
    #define AFX_EXT_API         AFX_API_EXPORT
    #define AFX_EXT_DATA        AFX_DATA_EXPORT
    #define AFX_EXT_DATADEF
    #else
    #define AFX_EXT_CLASS       AFX_CLASS_IMPORT
    #define AFX_EXT_API         AFX_API_IMPORT
    #define AFX_EXT_DATA        AFX_DATA_IMPORT
    #define AFX_EXT_DATADEF
    #endif
    #endif
    ————————————————
    原文链接:https://blog.csdn.net/tajon1226/java/article/details/55190247

    *********

    常记溪亭日暮,沉醉不知归路。兴尽晚回舟,误入藕花深处。争渡,争渡,惊起一滩鸥鹭。

    昨夜雨疏风骤,浓睡不消残酒。试问卷帘人,却道海棠依旧。知否?知否?应是绿肥红瘦。
  • 相关阅读:
    【Leetcode】23. Merge k Sorted Lists
    【Leetcode】109. Convert Sorted List to Binary Search Tree
    【Leetcode】142.Linked List Cycle II
    【Leetcode】143. Reorder List
    【Leetcode】147. Insertion Sort List
    【Leetcode】86. Partition List
    jenkins 配置安全邮件
    python 发送安全邮件
    phpstorm 同步远程服务器代码
    phpUnit 断言
  • 原文地址:https://www.cnblogs.com/htj10/p/11146191.html
Copyright © 2011-2022 走看看