动态链接库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.0\VC>dumpbin -exports D:\WorkSpace\DLLTutorial\Debug\DLLTutorial.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

 

 

 

 

*********

posted @ 2019-07-07 14:24  htj10  阅读(383)  评论(0编辑  收藏  举报
TOP