`
yanlijun250
  • 浏览: 783381 次
文章分类
社区版块
存档分类
最新评论

DLL动态链接库初学手迹(垃圾文,高手勿入)

 
阅读更多

还在大三的时候写的一篇垃圾文章,磁盘里的删了,最后就放个尸体在这里吧,也算是活了一趟的见证……

总论

伴随着软件规模的扩大,一个系统不再能由一个或几个人从头到尾全部维护,模块化设计制作成了产业的共识。<?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" />

也许说到模块,您就会想起class,的确,类是一种模块,但它却仅仅是一个创建时的模块,每次对某一个模块的小小修改,就会导致对所有其他模块的重新编译。也许对于现在的您,这重新编译仅仅不过是代码之余的一次简短的休憩,然而,当您写的不再是一个个小小的习作,而是和别人一起开发一个大的系统,特别是对这个系统进行后期测试的时侯,您会发现,那每次半个小时以上的编译可以给您足够的理由发疯。

DLL是另一种模块,它是运行时的模块。你可以把类封装到一个个小小的DLL里面,一块块单独测试,最后再把它们拼接到一起。这不仅仅是省时间的选择,而且,很多具有强扩展性的模块还可以发布给别人,当然同样您也可以从别人那里获得具有某个功能的DLL模块,以节约开发时间和成本。您可以在很多大型软件里面看到成堆的DLL,这无疑是它强盛的生命力的证据。当然,一个应用程序附带的文件应当越少越好,否则调入一次应用程序就要打开数百个磁盘文件,估计谁都受不了。

正如开始接触WinMain时的那种敬畏心理,很多人在面对DLL时有些不知所措。其实现在写DLL已经不是什么困难的事情了,而MFCDLL也有很好的支持。嗯,好的,费话不多说,让我们开始旅途。

Dll技术基础

在介绍如何去编写DLL之前,您应该明白DLL是如何工作的。

DLL表现为磁盘上一个个文件,它无法自行启动,只能等待别人来调用它——或者更确切的说,载入它以调用它里面储存的数据和函数。如果要用DLL,必须要把它们映射到应用程序进程的地址空间去,这是显而易见的事情,DLL就像一个雇佣兵,你如果要让它为你卖命,起码应该去载入它到你的军队(进程地址空间)中来。请注意这里,DLL一旦调入,只会在内存中保留一份页面,无论多少对它们的调用仅仅不过是把它们映射,而不像EXE那样,一次运行,就是一个全新的空间。DLL的真实所占空间是一定的,这对内存的节约也有好处。如果您想对DLL更全面的认识,请参阅Jeffrey Richter的《Advanced Windows》(中文版译名:《Windows核心编程》机械工业出版社)

DLL的连接

DllMainDLL的入口,您可以将之类比于WinMainDllMain在连接到进程和断开与进程的连接和其他响应时被调用。如果没有它,我们导入的函数什么都不会做。具体细节,请参照《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系统目录(SystemSystem32

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

MFCAppWizard提供了两种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共享DLLDLL例子。

<?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.dllSTDDLL.lib文件拷贝出来,STDDLL.dll放到系统文件夹(98Me的放到WindowsSystem文件夹下,NT2000XP的放到WinNTSystem32文件夹下),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中的MFCAppWizardDll),然后在紧接着的对话框中选择MFC Extension DLLMFC扩展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.hExtClass.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

    立象条码打印最新dll动态链接库4.04是一款专为条码打印设计的软件组件,它在IT行业中扮演着重要角色,特别是在自动化生产和物流管理领域。DLL(Dynamic Link Library)是Windows操作系统中的一种共享库,它封装了一...

    dll动态链接库和c++依赖库缺失修复工具

    动态链接库(DLL)是Windows操作系统中的一个重要组成部分,它是一种可执行文件,包含了程序运行时所需的函数和数据。DLL文件允许多个程序共享同一份代码和资源,从而节省内存并简化软件维护。当系统提示“dll动态...

    将现有的C++类转换成dll动态链接库

    ### 将现有的C++类转换成DLL动态链接库 #### 一、DLL的类型与选择 在考虑将现有的C++类转换成DLL时,首先需要理解不同类型的DLL及其适用场景。 1. **Win32DLL** Win32DLL指的是不使用MFC类库创建的DLL。这类DLL...

    qt5_dll动态链接库合集

    动态链接库(DLL)是Windows操作系统中的一个重要概念,它将共享代码和资源存储在单独的文件中,多个程序可以同时调用这些共享资源,以减少内存占用和提高系统效率。 "qt5_dll"标签明确指出这个压缩包包含的是与Qt5...

    C#版 OPC dll动态链接库全套合集.zip

    资源名:C#版 OPC dll动态链接库全套合集.zip 资源类型:程序源代码 源码说明: 这是基于C#版的 OPC dll动态链接库全套合集 可直接在工程程序中引用来使用 非常方便 适合人群:新手及有一定经验的开发人员

    DLL动态链接库

    MFC71动态链接库,为缺少改动态链接库的程序 注册既可用

    msxml4.dll mssoap30.dll 动态链接库

    msxml4.dll mssoap30.dll 动态链接库 短信 网关所需要的dll安装文件。

    S7.Net动态链接库DLL.rar

    《S7.Net动态链接库DLL在西门子PLC通讯中的应用详解》 在工业自动化领域,西门子PLC(可编程逻辑控制器)因其稳定性和灵活性被广泛应用。本文将详细探讨与标题“S7.Net动态链接库DLL.rar”相关的知识点,主要关注S7...

    modbus TCP dll 动态链接库 源码

    Modbus TCP DLL(动态链接库)源码是一个用于开发与Modbus TCP协议交互的应用程序的重要资源。Modbus是一种广泛使用的工业通信协议,特别是在自动化设备和系统之间交换数据时。了解和利用这个源码能帮助开发者深入...

    LabVIEW调用动态链接库DLL详细介绍(包会) .txt

    ### LabVIEW调用动态链接库DLL详解 #### 一、前言 在现代软件开发过程中,经常需要将一些复杂的功能封装成独立的模块或者库,以便于复用和维护。对于LabVIEW这样的图形化编程环境而言,能够有效地调用外部的动态...

    libeay32.dll 、 ssleay32.dll动态链接库

    在Windows操作系统中,`libeay32.dll` 和 `ssleay32.dll` 是两个非常重要的动态链接库文件,它们是OpenSSL库的一部分。OpenSSL是一个强大的安全套接层(SSL)和传输层安全(TLS)协议实现,同时也包含了一些用于加密...

    动态链接库dll学习教程

    动态链接库(DLL)学习教程 动态链接库(DLL)概念 动态链接库(DLL)是 Windows 系统的核心,也是 COM 技术的基础。DLL 可以简单地看成一种仓库,它提供给你一些可以直接拿来用的变量、函数或类。在仓库的发展史上经历...

    纯虚函数接口 实现的dll动态链接库,

    在C++编程中,动态链接库(DLL)是一种可共享的代码库,它可以在多个程序之间复用,有助于减少内存占用和提高程序的模块化。本示例中的"纯虚函数接口 实现的dll动态链接库"是一个设计模式,通过抽象类定义接口,并将...

    DLL动态链接库嵌入exe可执行文件

    标题“DLL动态链接库嵌入exe可执行文件”所涉及的知识点主要集中在动态链接库(DLL)与可执行文件(EXE)之间的嵌入技术。动态链接库是一种实现共享函数库的方式,它允许程序中只存放必要的代码部分,在运行时才被加载,...

    visual c++检测DLL动态链接库的版本号

    vc检测DLL的版本号

    dll动态链接库方法查看工具.zip

    《dll动态链接库方法查看工具详解》 DLL(Dynamic Link Library)动态链接库是Windows操作系统中的一种重要组件,它封装了各种功能函数和资源,供其他程序调用。本工具——"dll动态链接库方法查看工具",专门针对C/...

    VC++动态链接库(DLL)编程深入浅出(全).pdf

    对于想要深入了解VC++下DLL编程的开发者来说,《VC++动态链接库(DLL)编程深入浅出》这本书提供了丰富的理论知识和实践指导,非常适合初学者和有一定基础的开发人员阅读学习。 综上所述,无论是从理论层面还是实际...

    dll动态链接库查看、反编译工具5合1

    包含多个dll、exe文件查看及反编译工具 dllshow dll view ResourceHacker_V3.5.2_XiaZaiBa.exe Reflector(超级震撼功能vc\vb\sap.net程序一网打尽)

    mp3_dll动态链接库

    《深入理解MP3_Dll动态链接库及其应用》 在计算机编程领域,动态链接库(Dynamic Link Library,简称DLL)是一种共享代码的方式,允许多个应用程序同时使用同一段代码,节省内存资源并便于软件升级。本篇文章将围绕...

    怎样用VB编写.DLL动态链接库文件

    在Windows中,许多应用程序并不是一个完整的可执行文件,它们被分割成一些相对独立的动态链接库,即DLL文件,放置于系统中。当我们执行某一个程序时,相应的DLL文件就会被调用。

Global site tag (gtag.js) - Google Analytics