MFC-DLL

   DLL(Dynamic Link Library,动态链接库)是微软公司为Windows和OS/2操作系统设计一种供应用程序在运行时调用的共享函数库。DLL是应用程序的一种扩展,也是软件共享和重用的传统方法。
   DLL除了可同时被多个应用程序共享外,还可以在不改变调用接口(从而不需修改使用它的应用程序)的情况下,改进和升级里面的库函数。而且DLL与编写它的语言无关,例如,用VC生成的规则DLL,可以被VB、Delphi等生成的应用程序使用。
   DLL可以用多种语言和工具编写,我们这里只介绍如何使用MFC来编写和使用DLL。相关说明文档位于MSDN帮助的“目录\开发工具和语言\Visual Studio\Visual C++\常见编程方法\DLL\”中。




  (一)  DLL与静态链接库


     静态链接库Lib(Static Link Library),是在编译的链接阶段将库函数嵌入到应用程序的内部。如果系统中运行的多个应用程序都包含所用到的公共库函数,则必然造成很大的浪费。这样即增加了链接器的负担,也增大了可执行程序的大小,还加大了内存的消耗。Lib的好处是应用程序可以独立运行,而不需要在操作系统中另外安装对应的DLL。
     而DLL采用动态链接,对公用的库函数,系统只有一个拷贝(一般是位于系统目录的*.DLL文件),而且只有在应用程序真正调用时,才加载到内存。在内存中的库函数,也只有一个拷贝,可供所有运行的程序调用。当再也没有程序需要调用它时,系统会自动将其卸载,并释放其所占用的内存空间。


    DLL的缺点是应用程序不能独立运行,需要在操作系统中另外安装对应的DLL。例如,如果你的MFC项目被设置成“在共享DLL中使用MFC”的,则虽然生成的可执行程序很小,但是在其他没有安装Visual C++(运行环境)的机器上是不能直接运行的,需要另外安装MFC的动态链接库(如mfc90.dll)


   (二) 放置DLL的目录
为了使需要动态链接库的应用程序可以运行,需要将DLL文件放在操作系统能够找到的地方。Windows操作系统查找DLL的目录顺序为:
1. 所在目录——当前进程的可执行模块所在的目录,即应用程序的可执行文件(*.exe)所在的目录。
2. 当前目录——进程的当前目录。
3. 系统目录——Windows操作系统安装目录的系统子目录,如C:\Windows\ System32。可用GetSystemDirectory函数检索此目录的路径。
4. Windows目录——Windows操作系统安装目录,如C:\Windows\。可用GetWindowsDirectory函数检索此目录的路径。
5. 搜索目录——PATH环境变量中所包含的自动搜索路径目录,一般包含C:\Windows\和C:\Windows\System32\等目录。可在命令行用Path命令来查看和设置,也可以通过(在“我的电脑”右键菜单中选“属性”菜单项)“系统属性”中的环境变量,来查看或编辑“Path”系统变量和“PATH”用户变量。
       MFC DLL的类型
使用MFC编写的DLL,可以分成两大类:
      规则DLL——规则(regular)DLL中所包含的函数,可以被所有Windows应用程序使用;
      共享MFC——DLL中不包含MFC库函数,需要另外安装MFC动态链接库后才能使用;
      静态MFC——DLL中包含MFC库函数,可以脱离MFC动态链接库独立使用。
      扩展DLL——扩展(extension)DLL中所定义的类和函数,只能被所MFC应用程序使用。而且扩展DLL中不能包含MFC库函数,也需要另外安装MFC动态链接库后才能使用。




    (三)导出函数的方法
使用MFC创建DLL时,从项目中导出(export)函数到DLL文件的方法有:
使用模块定义文件(.def)。
使用__declspec(dllexport)关键字或其替代宏AFX_EXT_CLASS。
这两种方法是互斥的,对每个函数只需用一种方法即可。另外,DEF文件只能用来导出函数,不能用于导出整个类。导出C++类,必须用__declspec(dllexport)关键字或其替代宏AFX_EXT_CLASS。


1.DEF文件
模块定义(module definition)文件(.def)是包含一个或多个描述DLL各种属性的模块语句的文本文件。DEF文件必须至少包含下列模块定义语句:
文件中的第一个语句必须是LIBRARY语句。此语句将.def文件标识为属于DLL。LIBRARY语句的后面是DLL的名称(缺省为DLL项目名)。链接器将此名称放到DLL的导入库中。
EXPORTS语句列出名称,可能的话还会列出DLL导出函数的序号值。通过在函数名的后面加上@符和一个数字,给函数分配序号值。当指定序号值时,序号值的范围必须是从1到N,其中N是DLL导出函数的个数。
即,DEF文件的格式为:(在这两个语句之间,还可以加上可选的描述语句:DESCRIPTION "库描述串"。分号;后的文本内容行为注释)
; 库名.def
LIBRARY 库名
EXPORTS
函数名1 @1
函数名2 @2
……
函数名n @n
在使用MFC DLL向导创建MFC DLL项目时,VC会自动创建一个与项目同名但没有任何函数导出项的DEF文件(项目名.def),格式为:
; 项目名.def : 声明 DLL 的模块参数。


LIBRARY      "项目名"


EXPORTS
    ; 此处可以是显式导出
例如,项目名为RegDll的DEF文件(RegDll.def)的内容为:
; RegDll.def : 声明 DLL 的模块参数。


LIBRARY      "RegDll"


EXPORTS
; 此处可以是显式导出
如果生成扩展DLL并使用.def文件导出,则将下列代码放在包含导出类的头文件的开头和结尾:
#undef AFX_DATA
#define AFX_DATA AFX_EXT_DATA
// <你的头文件体>
#undef AFX_DATA
#define AFX_DATA
这些代码行确保内部使用的MFC变量或添加到类的变量是从扩展DLL导出(或导入)的。例如,当使用DECLARE_DYNAMIC派生类时,该宏扩展以将CRuntimeClass成员变量添加到类。省去这四行代码可能会导致不能正确编译或链接DLL,或在客户端应用程序链接到DLL时导致错误。
当生成DLL时,链接器使用.def文件创建导出(.exp)文件和导入库(.lib)文件。然后,链接器使用导出文件生成DLL文件。隐式链接到DLL的可执行文件在生成时链接到导入库。请注意,MFC本身就是使用.def文件从MFCx0.dll导出函数和类的。


2.关键字或宏
除了使用DEF文件来导出函数外,还可以在源程序中使用__declspec(dllexport)关键字或其替代宏AFX_EXT_CLASS:
#define AFX_EXT_CLASS  AFX_CLASS_EXPORT (定义在头文件afxv_dll.h中)
#define AFX_CLASS_EXPORT  __declspec(dllexport) (定义在头文件afxver_.h中)
来导出函数和整个C++类。
具体的格式为:
导出整个类:
class AFX_EXT_CLASS 类名[ : public基类]
{
……
}
导出类的成员函数:
class 类名[ : public基类]
{
AFX_EXT_CLASS 返回类型 函数名1(……) ;
AFX_EXT_CLASS 返回类型 函数名2(……) ;
……
}
导出外部C格式的(全局)函数:
extern "C" __declspec(dllexport) 返回类型 函数名(……) 
{
……
}
如果希望用MFC(C++)编写的规则DLL中的函数,也能够被非MFC程序来调用,需要为函数声明指定extern "C"。不然,C++编译器会使用C++类型安全命名约定(也称作名称修饰)和C++调用约定(使用此调用约定从C调用会很困难)。
为了使用方便,可以定义宏:
#define DllExport extern "C" __declspec(dllexport)
然后再使用它,例如:
DllExport int Add(int d1, int d2) {……}


    (四)由于通常使用DLL的时候,编写和调试的时候要将关系组织好,就是相互的依赖关系,还 要设置好工作目录(这个很重要)
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值