关于DLL的小结

在使用VS建立DLL工程时,可以创建不同类型的dll。

  1. 可以通过点击win32项目,创建dll,此时创建的dll为普通的dll,与MFC无关。其项目属性->配置属性->常规->MFC的使用 的标签为使用标准Windows库
  2. 可以通过点击MFC DLL选择创建三种不同的DLL
    (1)使用共享MFC DLL的规则DLL(在共享 DLL 中使用 MFC)
    (2)带静态链接MFC的规则DLL(在静态库中使用 MFC)
    (3)MFC扩展DLL(在共享 DLL 中使用 MFC)

规则DLL与扩展DLL区别
前两种dll为规则dll,在规则dll内部可以使用MFC,但是其接口不能是基于MFC的,其要能够被所有支持dll的编程语言所写的应用程序使用。*
MFC扩展DLL内部也可以使用MFC,其与应用程序接口可以是MFC,可以是从MFC扩展dll中导出一个MFC的派生类。
MFC的扩展DLL的内涵是MFC的扩展,其主要功能是实现从现有MFC库类中派生出可重用的类。用户使用MFC的扩展DLL就像使用MFC本身的DLL一样,除了可以在MFC的扩展DLL内部使用MFC外,MFC的扩展DLL与应用程序的接口也可以是MFC,一般使用MFC的扩展DLL来增强MFC的功能。MFC扩展DLL使用MFC 动态链接库版本,因此只有用==共享MFC版本生成的MFC可执行文件(应用程序或规则DLL)==才能使用MFC扩展DLL。此类dll一般很少用。
使用VS新建的扩展DLL工程与规则DLL工程的工程文件也存在较大差距。

设置为“在共享 DLL 中使用 MFC”的dll
若DLL设置的是在共享 DLL 中使用 MFC,则在编写基于MFC的DLL程序时,编译后该DLL中不包含MFC的库,而是由dll运行的时候动态链接到MFC的库。因此,当发布的DLL设置的是在共享 DLL 中使用 MFC时,如果对方的机器上没有安装MFC的库,那么该dll是运行不了的,除非你将MFC的库也一块给他。

设置为“在共享 DLL 中使用 MFC”的DLL的模块切换:
系统加载该类dll时,会涉及到多个dll的加载,那么如果当DLL和应用程序中存在相同ID的资源时,系统不能正确分辨程序员的意图,因此,我们需要通过模块切换来找到正确的资源模块,并进行对应的操作。
DLL的内部运行机制:
应用程序进程本身及其调用的每个DLL模块都具有一个全局唯一的HINSTANCE句柄,它们代表了DLL或EXE模块在进程虚拟空间中的起始地址。进程本身的模块句柄一般为0x400000,而DLL模块的缺省句柄为0x10000000。如果程序同时加载了多个DLL,则每个DLL模块都会有不同HINSTANCE。EXE和DLL都有其自己的资源,而且这些资源的ID可能重复,应用程序需要通过资源模块的切换来找到正确的资源。
如果应用程序需要来自于DLL的资源,就应将资源模块句柄指定为DLL的模块句柄;如果需要EXE文件中包含的资源,就应将资源模块句柄指定为EXE的模块句柄。
为了完成模块切换,在所有从DLL输出的函数中都应该使用以下语句开头:
AFX_MANAGE_STATE(AfxGetStaticModuleState( ))作为接口的第一条语句进行模块状态转换;
AFX_MOUDLE_STATE * AFXAPI AfxGetStaticModuleState(),
该函数返回当前模块状态;
AFX_MANAGE_STATE(AFX_MOUDLE_STATE * pMoudleState),
该宏用于将pMoudleState设置为当前模块状态,当宏的作用域结束后,也就是离开pMoudleState所指向栈上对象的作用域时,AFX_MOUDLE_STATE的析构函数完成模块状态的恢复;
AfxGetResourceHandle(),
获取程序当前正在使用的模块句柄;
AfxSetResourceHandle(),
设置程序需要使用的模块句柄,在接口函数开始时进行模块状态转换;
HINSTANCE old_hInstance=AfxGetResourceHandle(); AfxSetResourceHandle(当前dll的句柄,可以使用theApp.m_hInstance);
后面是函数的其余部分,
结尾处AfxSetResourceHandle(old_hInstance);将模块状态再次转换过来,该方法可以用在dll中,也可以用在应用程序调用该dll函数之前之后;

设置为“在静态库中使用 MFC”的DLL:
将MFC dll编译到自身内部,但是程序较大一些,其中包含必要的库文件,可以保证在没有安装安装MFC库的机器上正常运行。

DLL导出
DLL输出函数的方法:
(1) 在.def文件中声明:如:
; lib.def : 导出DLL函数
LIBRARY dllTest(dll名称可忽略,但需要和生成的名称一致)
EXPORTS
Add @ 1
以”;”开始的为注释行,上述例子表示:生成名为“dllTest”的动态链接库,导出其中的add函数,序号为1。该序号在函数调用时起作用:GetProcAddress ( hDll, MAKEINTRESOURCE ( n ))返回 def定义的第n个函数地址。

本人最常用第二种方法
(2)使用MFC提供的修饰符号_declspec(dllexport);
要输出整个的类,对类使用_declspec(_dllexpot);要输出类的成员函数,则对该函数使用_declspec(_dllexport)。如:
class _declspec(_dllexport) CTextDoc : public CDocument
{}

若要同时生成dll和lib文件,要添加导出标识

extern “C” int__declspec(dllexport)add(int x, int y);
(3)对链接程序LINK指定/EXPORT命令行参数,输出有关函数。

LIb文件与DLL文件
共有两种LIB文件:
一种是LIB包含了函数所在的DLL文件和文件中函数位置的信息(入口),代码由运行时加载在进程空间中的DLL提供。
一种是LIB包含函数代码本身,在编译时直接将代码加入程序当中。(与上文讲到的“在静态库中使用 MFC”类似)
生成DLL时,会同时生成第一种LIB文件,在此只对第一种LIB文件详细解释。
第一种LIB文件
第一种LIB文件
第一种LIB文件
LIB是编译时用到的,dll是运行时用到的。如果要完成源代码的编译,只需要LIB;如果要使动态链接的程序运行起来,可以使用LIB+DLL(静态调用),也可以只使用DLL(动态调用)。
LIB包含被DLL导出的函数名称和位置,DLL包含实际的函数和数据,应用程序使用LIB文件链接到DLL文件。在应用程序的可执行文件中,存放的不是被调用的函数代码,而是DLL中相应函数代码的地址,从而节省了内存资源。

DLL调用
使用动态链接库的时,往往提供两个文件:静态库文件(LIB)和动态链接库(DLL)。静态库文件(LIB)包含动态连接库(DLL)所有导出的函数和变量的符号名和地址,动态连接库(DLL)包含实际的函数和数据。调用方式分为动态调用(显式链接)和静态调用(隐式链接)。

1、 静态调用(隐式链接)
由编译系统完成对DLL的加载和卸载。共需两步操作:

告诉编译器与DLL相对应的LIB文件所在的路径及文件名;

声明导入函数,如:extern “C” __declspec(dllimport)add(int x,int y)(若有导出函数声明的头文件可直接包含该.h文件);

在静态调用时,调用DLL的工程要用到.h、LIB、DLL文件
首先
.h文件
工程—属性—配置属性—c/c+±–常规—附加包含目录(Additional Include Directories):加上头文件存放目录。
LIB文件
添加文件引用的lib静态库路径:工程—属性—配置属性—链接器—常规—附加库目录(Additional Library Directory):加上LIB文件存放目录
然后添加工程引用的lib文件名:工程—属性—配置属性—链接器—输入—附加依赖项(Additional Dependencies):加上LIB文件名。
DLL文件
把引用的dll放到工程的可执行文件所在的目录(DeBug文件夹)下,如不添加,编译连接不会报错,运行报错:无法找到***.dll文件。

容易产生无法解析的外部符号:优先考虑配置问题,主要是链接库的配置,lib配置是否正确。
其次要添加导出标志是否添加正确:注意_declspec(_dllexpot)添加到Class标识符后面,类名称前面。
考虑平台配置是否正确,是否建立了debug\release\win32\x64等平台

2、 动态调用(显示链接)
使用Win32 API 函数LoadLibrary、GetProcAddress、FreeLibrary实现"DLL加载-DLL函数地址获取-DLL释放”。这种方法不需要LIB文件,只需要DLL文件即可,显式链接速度更快且更加灵活。

对DLL添加父类
在实际开发过程中,要用到C++多态的特性,需要对已经存在的DLL子类添加父类。就好比是子类调用父类,添加流程为:

新建父类空项目,项目类型为MFC DLL,对父类添加导出标志,设置输出文件的路径,输出路径为子类DLL存在的路径;

对导出类进行设置:添加库目录、附加库目录、附加依赖项

设置依赖顺序,要保证先生成父类,再生成子类。

参考文献1
参考文献2
参考文献3
参考文献4
参考文献5
参考文献6
参考文献7

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值