还在大三的时候写的一篇垃圾文章,磁盘里的删了,最后就放个尸体在这里吧,也算是活了一趟的见证……
总论
伴随着软件规模的扩大,一个系统不再能由一个或几个人从头到尾全部维护,模块化设计制作成了产业的共识。<?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" />
也许说到模块,您就会想起class,的确,类是一种模块,但它却仅仅是一个创建时的模块,每次对某一个模块的小小修改,就会导致对所有其他模块的重新编译。也许对于现在的您,这重新编译仅仅不过是代码之余的一次简短的休憩,然而,当您写的不再是一个个小小的习作,而是和别人一起开发一个大的系统,特别是对这个系统进行后期测试的时侯,您会发现,那每次半个小时以上的编译可以给您足够的理由发疯。
DLL是另一种模块,它是运行时的模块。你可以把类封装到一个个小小的DLL里面,一块块单独测试,最后再把它们拼接到一起。这不仅仅是省时间的选择,而且,很多具有强扩展性的模块还可以发布给别人,当然同样您也可以从别人那里获得具有某个功能的DLL模块,以节约开发时间和成本。您可以在很多大型软件里面看到成堆的DLL,这无疑是它强盛的生命力的证据。当然,一个应用程序附带的文件应当越少越好,否则调入一次应用程序就要打开数百个磁盘文件,估计谁都受不了。
正如开始接触WinMain时的那种敬畏心理,很多人在面对DLL时有些不知所措。其实现在写DLL已经不是什么困难的事情了,而MFC对DLL也有很好的支持。嗯,好的,费话不多说,让我们开始旅途。
Dll技术基础
在介绍如何去编写DLL之前,您应该明白DLL是如何工作的。
DLL表现为磁盘上一个个文件,它无法自行启动,只能等待别人来调用它——或者更确切的说,载入它以调用它里面储存的数据和函数。如果要用DLL,必须要把它们映射到应用程序进程的地址空间去,这是显而易见的事情,DLL就像一个雇佣兵,你如果要让它为你卖命,起码应该去载入它到你的军队(进程地址空间)中来。请注意这里,DLL一旦调入,只会在内存中保留一份页面,无论多少对它们的调用仅仅不过是把它们映射,而不像EXE那样,一次运行,就是一个全新的空间。DLL的真实所占空间是一定的,这对内存的节约也有好处。如果您想对DLL更全面的认识,请参阅Jeffrey Richter的《Advanced Windows》(中文版译名:《Windows核心编程》机械工业出版社)
DLL的连接
DllMain是DLL的入口,您可以将之类比于WinMain。DllMain在连接到进程和断开与进程的连接和其他响应时被调用。如果没有它,我们导入的函数什么都不会做。具体细节,请参照《Windows核心编程》。
DLL可以隐式或者显式连接到进程中。在DLL中包含有一个导出函数表,客户程序装入DLL时,可以通过函数的符号化名字来得到这些函数,然后通过函数表得到这些函数在DLL模块内的地址,继而通过这些地址调用函数。
DLL中,我们通过以下的方式声明函数Fun是要被导出的:
extern “C” __declspec(dllexport) int Fun();
由于有些DLL需要调用别的DLL的函数,因此,某些DLL也会设置导入:
extern “C” __declspec(dllimport) int Fun2();
如果我们要使用刚刚的DLL导出的函数,需要这样:
extern “C” __declspec(dllimport) int Fun();
当然,同时需要把与Dll一起生成的Lib文件加入到工程中,而且,“客户程序必须至少调用了DLL导出函数中的一个函数”。LIB文件中记载的是DLL的导出符号,只有通过它我们才能够得知要调用哪些函数。在编译完进行链接的时候,LIB中的这些符号被匹配并绑定到EXE文件中,EXE同时保存下来LIB中的DLL文件名。当程序开始运行的时候,EXE去到下面几个地方找到DLL并装载,然后在运行时动态链接DLL中的功能:
1、当前运行进程的EXE的所在目录
2、进程当前目录
3、Windows系统目录(System/System32)
4、Windows目录
5、Path环境变量里列出的目录
显式连接不需要LIB文件,直接调用LoadLibrary(“DLL路径名”)就可以完成。如下:
HINSTANCE hInst;
hInstance = LoadLibary(“DLL路径名”);
如果要使用刚刚DLL导出的函数,现在需要这么做:
SORTPROC* pFun;
pFun = (SORTPROC*) GetProcAddress(hInstance , “Fun”);
int ret = (*pFun)();
显式连接的好处是可以根据需要在任何时候装载DLL,而隐式连接则在一开始就装载了所有的DLL。
用MFC来做DLL
正规的DLL和扩展的DLL
MFC的AppWizard提供了两种DLL的支持:扩展的DLL和正规的DLL。正规的DLL可以被任何一个Win32开发环境装载,不过它只能导出C风格的函数,而不能导出C++类、成员函数或者重载函数,但我们可以在正规DLL中使用这些东西。
而扩展的DLL可以导出整个C++类,但是它要求比较高:首先客户程序必须动态链接到MFC库,而且和要用的扩展DLL连接到同一个版本的MFC DLL。
一个正规DLL的例子
创建正规DLL时可以选择静态或者动态(使用MFC共享DLL)链接到MFC库。如果选择了静态链接,则DLL将包括所有它需要的MFC库代码的拷贝,这样一个DLL会比较大,但是可以独立运用,不再需要去考虑运行环境是否会有MFC支持。使用共享的MFC DLL则会小一些,但是必须保证客户机器上有相应的MFC DLL。
下面就是一个生成使用MFC共享DLL的DLL例子。
<?xml:namespace prefix = v ns = "urn:schemas-microsoft-com:vml" /><shapetype id="_x0000_t75" stroked="f" filled="f" path="m@4@5l@4@11@9@11@9@5xe" o:preferrelative="t" o:spt="75" coordsize="21600,21600"><stroke joinstyle="miter"></stroke><formulas><f eqn="if lineDrawn pixelLineWidth 0"></f><f eqn="sum @0 1 0"></f><f eqn="sum 0 0 @1"></f><f eqn="prod @2 1 2"></f><f eqn="prod @3 21600 pixelWidth"></f><f eqn="prod @3 21600 pixelHeight"></f><f eqn="sum @0 0 1"></f><f eqn="prod @6 1 2"></f><f eqn="prod @7 21600 pixelWidth"></f><f eqn="sum @8 21600 0"></f><f eqn="prod @7 21600 pixelHeight"></f><f eqn="sum @10 21600 0"></f></formulas><path o:connecttype="rect" gradientshapeok="t" o:extrusionok="f"></path><lock aspectratio="t" v:ext="edit"></lock></shapetype>
点击完成,主要生成了一个stddll.h和一个stddll.cpp。
现在,在stddll.cpp中加入我们要导出的函数,假设是一个平方函数:
extern “C” __declspec(dllexport) int DllFunction(int val)
{
AFX_MANAGE_STATE(AfxGetStaticModuleState()); //注意这一句一定要有
return val*val;
}
下面我们需要测试这个DLL,新建一个MFC的对话框项目:
注意这里一定要选择当共享DLL。
现在我们为这个对话框添加三个控件:一个按扭,两个编辑框。然后按照如下方式设置控件:
控件ID
| 数据
| 函数
|
IDC_CLICK
|
| OnClick
|
IDC_IN
| m_iInput
|
|
IDC_OUT
| m_iOutput
|
|
首先我们要导入DllFunction,在TESTDLLDLG.H文件中添加:
extern “C” __declspec(dllimport) int DllFunction(int val);
写OnClick函数如下:
void CTESTDLLDlg::OnClick()
{
// TODO: Add your control notification handler code here
UpdateData(TRUE);
m_iOutput = DllFunction(m_iInput);
UpdateData(FALSE);
}
好了,编译下,不成功对吧,呵呵,我们还没有告诉MFC去哪里找DLL呢,那该怎么办呢?先把刚刚DLL工程的Debug文件夹下面的STDDLL.dll和STDDLL.lib文件拷贝出来,STDDLL.dll放到系统文件夹(98/Me的放到Windows/System文件夹下,NT/2000/XP的放到WinNT/System32文件夹下),STDDLL.lib放到当前TESTDLL工程的Debug文件夹下,然后作如下设置,在“工程”菜单下面找到“设置”:
在“对象/库模块”里面添加那样一句就可以了,这里用的是相对工程文件夹的路径,如果您用了别的工程设置方式,只需要这里添上相对于工程相应的.dsp文件的相对路径就可以。
下面再运行就应该成功了,结果如下:
总结一下,DLL方要完成的任务:
1、生成正规DLL项目。
2、在cpp文件中按格式添加所需要的函数。
Exe方要完成的任务:
1、在cpp文件中完成对dll中函数的调用。
2、在cpp相应的h文件中用__declspec(import)声明DLL要导出的函数。
3、完成对LIB路径的设置,并且最重要的,把DLL拷贝到EXE能找到它的地方。
其实在上面的例子中,你完全可以不把dll文件拷到系统目录下,而是拷贝到TESTDLL工程的Debug文件夹下,因为TESTDLL工程生成的Exe文件肯定在那里,这样,DLL就一定会在EXE可以找到的地方了。如果您有兴趣,还可以将DLL拷贝到别的地方试试看。
一个扩展DLL的例子
运行AppWizard,产生Projects中的MFCAppWizard(Dll),然后在紧接着的对话框中选择MFC Extension DLL(MFC扩展DLL)。如图:
然后,会主要产生下面的代码和一个Def文件:
// EXTDLL.cpp : Defines the initialization routines for the DLL.
//
#include "stdafx.h"
#include <afxdllx.h>
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
static AFX_EXTENSION_MODULE EXTDLLDLL = { NULL, NULL };
extern "C" int APIENTRY
DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID lpReserved)
{
// Remove this if you use lpReserved
UNREFERENCED_PARAMETER(lpReserved);
if (dwReason == DLL_PROCESS_ATTACH)
{
TRACE0("EXTDLL.DLL Initializing!/n");
// Extension DLL one-time initialization
if (!AfxInitExtensionModule(EXTDLLDLL, hInstance))
return 0;
//这里删掉了注释
new CDynLinkLibrary(EXTDLLDLL);
}
else if (dwReason == DLL_PROCESS_DETACH)
{
TRACE0("EXTDLL.DLL Terminating!/n");
// Terminate the library before destructors are called
AfxTermExtensionModule(EXTDLLDLL);
}
return 1; // ok
}
加入新的类:ExtClass.h和ExtClass.cpp,在ExtClass.h中添下如下代码:
#pragma once
#ifdef _WINDLL
#define DLL __declspec(dllexport)
#else
#define DLL
#endif
class DLL CExtDll
{
BOOL m_iNum;
public :
CExtDll();
~CExtDll();
void DllMessageBox(LPSTR pszString);
void Func(int i);
int ReturnVal();
} ;
在.cpp中添加:
#include "stdafx.h"
#include "ExtClass.h"
CExtDll:: CExtDll ( )
{
m_iNum = 255 ;
}
CExtDll:: ~CExtDll()
{ }
void CExtDll::DllMessageBox(LPSTR pszString)
{
AfxMessageBox ( pszString ) ;
}
void CExtDll::Func(int i)
{
m_iNum = i;
}
int CExtDll::ReturnVal()
{
return m_iNum;
}
然后编译,得到.lib和.dll文件。
然后建立一个基于对话框的工程TestExtDll,设置基本与TestDll相同。然后做如下设置:
1、添加一个编辑框控件,利用Class Wizzard添加成员变量int类型的m_iNum。
2、为确定按钮添加事件OnOK:在TestExtDllDlg.cpp中写下如下代码:
先是在最开头写一句:
#include “ExtClass.h”
这个.h文件应该从那个ExtDll工程中原封不动的拷贝过来。
然后为OnOK添加代码:
void CTestExtDllDlg::OnOK()
{
// TODO: Add extra validation here
UpdateData(TRUE);
//注意下面这几句,完成对Dll中类的调用
CExtDll aDll;
aDll.DllMessageBox("Hello : )!!");
aDll.Func(88);
m_iNum = aDll.ReturnVal();
UpdateData(FALSE);
}
3、然后把ExtDll工程生成的.lib和.dll文件如下处理:
3a、拷贝到当前TestExtDll工程的Debug文件夹下
3b、在工程-设置-link选项卡中,对“对象/库模块”中加入debug/ExtDll.lib。
最后编译,结果如下:
看起来也不是很困难吧。
到这里我们已经把MFC Dll制作的基本思路说完了,如果对Dll仍有疑问,请参照《Visual C++技术内幕》(清华大学出版社)等经典教材。
分享到:
相关推荐
立象条码打印最新dll动态链接库4.04是一款专为条码打印设计的软件组件,它在IT行业中扮演着重要角色,特别是在自动化生产和物流管理领域。DLL(Dynamic Link Library)是Windows操作系统中的一种共享库,它封装了一...
动态链接库(DLL)是Windows操作系统中的一个重要组成部分,它是一种可执行文件,包含了程序运行时所需的函数和数据。DLL文件允许多个程序共享同一份代码和资源,从而节省内存并简化软件维护。当系统提示“dll动态...
### 将现有的C++类转换成DLL动态链接库 #### 一、DLL的类型与选择 在考虑将现有的C++类转换成DLL时,首先需要理解不同类型的DLL及其适用场景。 1. **Win32DLL** Win32DLL指的是不使用MFC类库创建的DLL。这类DLL...
动态链接库(DLL)是Windows操作系统中的一个重要概念,它将共享代码和资源存储在单独的文件中,多个程序可以同时调用这些共享资源,以减少内存占用和提高系统效率。 "qt5_dll"标签明确指出这个压缩包包含的是与Qt5...
资源名:C#版 OPC dll动态链接库全套合集.zip 资源类型:程序源代码 源码说明: 这是基于C#版的 OPC dll动态链接库全套合集 可直接在工程程序中引用来使用 非常方便 适合人群:新手及有一定经验的开发人员
MFC71动态链接库,为缺少改动态链接库的程序 注册既可用
msxml4.dll mssoap30.dll 动态链接库 短信 网关所需要的dll安装文件。
《S7.Net动态链接库DLL在西门子PLC通讯中的应用详解》 在工业自动化领域,西门子PLC(可编程逻辑控制器)因其稳定性和灵活性被广泛应用。本文将详细探讨与标题“S7.Net动态链接库DLL.rar”相关的知识点,主要关注S7...
Modbus TCP DLL(动态链接库)源码是一个用于开发与Modbus TCP协议交互的应用程序的重要资源。Modbus是一种广泛使用的工业通信协议,特别是在自动化设备和系统之间交换数据时。了解和利用这个源码能帮助开发者深入...
### LabVIEW调用动态链接库DLL详解 #### 一、前言 在现代软件开发过程中,经常需要将一些复杂的功能封装成独立的模块或者库,以便于复用和维护。对于LabVIEW这样的图形化编程环境而言,能够有效地调用外部的动态...
在Windows操作系统中,`libeay32.dll` 和 `ssleay32.dll` 是两个非常重要的动态链接库文件,它们是OpenSSL库的一部分。OpenSSL是一个强大的安全套接层(SSL)和传输层安全(TLS)协议实现,同时也包含了一些用于加密...
动态链接库(DLL)学习教程 动态链接库(DLL)概念 动态链接库(DLL)是 Windows 系统的核心,也是 COM 技术的基础。DLL 可以简单地看成一种仓库,它提供给你一些可以直接拿来用的变量、函数或类。在仓库的发展史上经历...
在C++编程中,动态链接库(DLL)是一种可共享的代码库,它可以在多个程序之间复用,有助于减少内存占用和提高程序的模块化。本示例中的"纯虚函数接口 实现的dll动态链接库"是一个设计模式,通过抽象类定义接口,并将...
标题“DLL动态链接库嵌入exe可执行文件”所涉及的知识点主要集中在动态链接库(DLL)与可执行文件(EXE)之间的嵌入技术。动态链接库是一种实现共享函数库的方式,它允许程序中只存放必要的代码部分,在运行时才被加载,...
vc检测DLL的版本号
《dll动态链接库方法查看工具详解》 DLL(Dynamic Link Library)动态链接库是Windows操作系统中的一种重要组件,它封装了各种功能函数和资源,供其他程序调用。本工具——"dll动态链接库方法查看工具",专门针对C/...
对于想要深入了解VC++下DLL编程的开发者来说,《VC++动态链接库(DLL)编程深入浅出》这本书提供了丰富的理论知识和实践指导,非常适合初学者和有一定基础的开发人员阅读学习。 综上所述,无论是从理论层面还是实际...
包含多个dll、exe文件查看及反编译工具 dllshow dll view ResourceHacker_V3.5.2_XiaZaiBa.exe Reflector(超级震撼功能vc\vb\sap.net程序一网打尽)
《深入理解MP3_Dll动态链接库及其应用》 在计算机编程领域,动态链接库(Dynamic Link Library,简称DLL)是一种共享代码的方式,允许多个应用程序同时使用同一段代码,节省内存资源并便于软件升级。本篇文章将围绕...
在Windows中,许多应用程序并不是一个完整的可执行文件,它们被分割成一些相对独立的动态链接库,即DLL文件,放置于系统中。当我们执行某一个程序时,相应的DLL文件就会被调用。