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

    *********

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

    昨夜雨疏风骤,浓睡不消残酒。试问卷帘人,却道海棠依旧。知否?知否?应是绿肥红瘦。
  • 相关阅读:
    paip.python错误解决21
    【Linux入门学习之】vi/vim编辑器必知必会
    深入理解C/C++数组和指针
    《当幸福来敲门》的经典对话
    matlab与excel xlsread、xlswrite实用方法
    vim复制粘贴的命令
    深入理解C/C++数组和指针
    vim复制粘贴的命令
    matlab与excel xlsread、xlswrite实用方法
    【Linux入门学习之】vi/vim编辑器必知必会
  • 原文地址:https://www.cnblogs.com/htj10/p/11146191.html
Copyright © 2011-2022 走看看