windows动态链接库由浅入深

合集下载

dll 原理

dll 原理

dll 原理DLL(Dynamic-Link Library)是一种Windows操作系统中常用的动态链接库。

它是一种可执行模块,包含可供程序调用的函数和数据,可以被多个应用程序共享。

在程序运行时,程序可以动态地载入和卸载DLL,从而实现模块化编程的方式。

本文将介绍DLL的原理和相关内容。

一、DLL的作用1. 动态链接:DLL的一个主要作用就是实现动态链接。

动态链接是指在程序运行期间,将DLL中的代码载入内存并链接,再去调用DLL中的函数和数据,以实现程序功能。

与静态链接方式相比,动态链接具有更好的灵活性,可以使程序的运行速度更快,占用内存更少。

2. 模块化编程:通过使用DLL,程序员可以将程序的功能划分为多个模块,从而实现模块化编程,提高代码的可重用性和可维护性。

在不同的应用程序中,可以共享同一模块的代码和数据,避免代码冗余。

3. 插件机制:另一个重要的作用是实现插件机制。

通过使用DLL,程序员可以设计并开发插件,将其作为动态链接库,供其他程序使用。

这使得程序有了更好的扩展性和可配置性。

二、DLL的实现原理1. 建立与卸载:程序载入DLL时,需要在内存中建立一个DLL实例,为DLL分配一块内存,并将DLL的函数地址表加载到内存中。

程序使用DLL的函数时,会根据函数地址表进行调用。

当程序不再需要使用DLL时,可以卸载DLL,释放内存空间。

2. 导出函数表:为了使DLL中的函数能够被其他程序调用,需要在DLL中建立一个导出函数表,记录DLL中所包含的全部函数。

三、DLL的使用方法1. 导出函数:为了使其他应用程序能够调用DLL中的函数,需要在DLL中声明函数为导出函数。

在VC++中,可以使用__declspec(dllexport)关键字来声明函数为导出函数。

2. 导入函数:在同一工程中使用DLL的函数时,需要相应地导入DLL中的函数。

在VC++中,可以使用__declspec(dllimport)关键字来声明函数为导入函数。

动态链接库(DLL)编程深入浅出(3)精品文档11页

动态链接库(DLL)编程深入浅出(3)精品文档11页

第4节我们对非MFC DLL进行了介绍,这一节将详细地讲述MFC规则DLL的创建与使用技巧。

另外,自从本文开始连载后,收到了一些读者的e-mail。

有的读者提出了一些问题,笔者将在本文的最后一次连载中选取其中的典型问题进行解答。

由于时间的关系,对于读者朋友的来信,笔者暂时不能一一回复,还望海涵!由于笔者的水平有限,文中难免有错误和纰漏,也热诚欢迎读者朋友不吝指正!MFC规则DLL的概念体现在两方面:(1)它是MFC的“是MFC的”意味着可以在这种DLL的内部使用MFC;(2)它是规则的“是规则的”意味着它不同于MFC扩展DLL,在MFC规则DLL的内部虽然可以使用MFC,但是其与应用程序的接口不能是MFC。

而MFC扩展DLL与应用程序的接口可以是MFC,可以从MFC扩展DLL中导出一个MFC类的派生类。

Regular DLL能够被所有支持DLL技术的语言所编写的应用程序调用,当然也包括使用MFC的应用程序。

在这种动态连接库中,包含一个从CWinApp继承下来的类,DllMain 函数则由MFC自动提供。

Regular DLL分为两类:(1)静态链接到MFC 的规则DLL静态链接到MFC的规则DLL与MFC库(包括MFC扩展DLL)静态链接,将MFC 库的代码直接生成在.dll文件中。

在调用这种DLL的接口时,MFC使用DLL的资源。

因此,在静态链接到MFC 的规则DLL中不需要进行模块状态的切换。

使用这种方法生成的规则DLL其程序较大,也可能包含重复的代码。

(2)动态链接到MFC 的规则DLL动态链接到MFC 的规则DLL 可以和使用它的可执行文件同时动态链接到MFC DLL 和任何MFC扩展DLL。

在使用了MFC共享库的时候,默认情况下,MFC使用主应用程序的资源句柄来加载资源模板。

这样,当DLL和应用程序中存在相同ID的资源时(即所谓的资源重复问题),系统可能不能获得正确的资源。

因此,对于共享MFC DLL的规则DLL,我们必须进行模块切换以使得MFC能够找到正确的资源模板。

动态链接库的使用方法

动态链接库的使用方法

动态链接库的使用方法动态链接库(Dynamic Link Library,DLL)是Windows系统中一种常见的文件类型,用于存储可被程序在运行时动态加载的函数和数据。

它可以提供代码和资源的共享,使得程序的安装包更小,节省了系统资源。

使用动态链接库有以下几个优点:1.模块化:将程序代码和资源划分为独立的模块,便于开发和维护。

2.共享性:多个程序可以共享同一个动态链接库,减少重复的代码和数据的存储。

3.动态加载:可以在程序运行时动态地加载和卸载动态链接库,提高了程序的灵活性和可扩展性。

1.创建动态链接库:使用C/C++编程语言可以创建动态链接库。

首先,在开发环境中创建新的DLL项目,并选择动态链接库的类型。

在项目中添加需要的代码和资源,并编写相应的函数和数据接口。

将这些接口封装在一个头文件中,并在源文件中实现具体的功能。

最后,编译项目生成动态链接库文件(.dll 文件)。

2.导出函数和数据:在动态链接库中,明确指定哪些函数和数据需要被其他程序调用。

在函数和数据的声明前加上__declspec(dllexport)关键字即可。

例如:```C++__declspec(dllexport) int Add(int a, int b);```3.调用动态链接库:在其他程序中调用动态链接库中的函数和数据,需要先导入相应的函数和数据。

使用C/C++编程语言可以创建一个头文件,其中包含要导入的函数和数据的声明。

例如:```C++__declspec(dllimport) int Add(int a, int b);__declspec(dllimport) extern double PI;```然后,在使用这些函数和数据的源文件中包含这个头文件即可。

4.加载和卸载动态链接库:在程序运行时,需要动态地加载动态链接库,并在使用完之后卸载。

可以使用LoadLibrary函数来加载动态链接库,使用FreeLibrary函数来卸载动态链接库。

C基础语法梳理:Windows的动态链接库

C基础语法梳理:Windows的动态链接库

C基础语法梳理:Windows的动态链接库https:///is/RhWSw8D/?=windows核心编程Windows 应用程序入口函数GUI(Graphical User Interface)应用,链接器选项:/SUBSYSTEM:WINDOWSCUI(Console User Interface)应用,链接器选项:/SUBSYSTEM:CONSOLE_tWinMain 与 _tmain 函数声明Int WINAPI _tWinMain( HINSTANCE hInstanceExe, HINSTANCE, PTSTR pszCmdLine, int nCmdShow);int _tmain( int argc, TCHAR *argv[], TCHAR *envp[]);Windows 的动态链接库(Dynamic-Link Library)部分知识点来自《Windows 核心编程(第五版)》用处(1)扩展了应用程序的特性(2)简化了项目管理(3)有助于节省内存(4)促进了资源的共享(5)促进了本地化(6)有助于解决平台间的差异(7)可以用于特殊目的注意(1)创建 DLL,事实上是在创建可供一个可执行模块调用的函数(2)当一个模块提供一个内存分配函数(malloc、new)的时候,它必须同时提供另一个内存释放函数(free、delete)(3)在使用 C 和 C++ 混编的时候,要使用 extern 'C' 修饰符(4)一个 DLL 可以导出函数、变量(避免导出)、C++ 类(导出导入需要同编译器,否则避免导出)(5)DLL 模块:cpp 文件中的__declspec(dllexport) 写在include 头文件之前(6)调用DLL 的可执行模块:cpp 文件的__declspec(dllimport) 之前不应该定义 MYLIBAPI加载 Windows 程序的搜索顺序1、包含可执行文件的目录2、Windows 的系统目录,可以通过 GetSystemDirectory 得到3、16 位的系统目录,即 Windows 目录中的 System 子目录4、Windows 目录,可以通过 GetWindowsDirectory 得到5、进程的当前目录6、PATH 环境变量中所列出的目录DLL 入口函数DllMain 函数BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved){ switch(fdwReason) { case DLL_PROCESS_ATTACH: // 第一次将一个DLL映射到进程地址空间时调用 // The DLL is being mapped into the process' address space. break; case DLL_THREAD_ATTACH: // 当进程创建一个线程的时候,用于告诉DLL执行与线程相关的初始化(非主线程执行) // A thread is bing created. break; case DLL_THREAD_DETACH: // 系统调用 ExitThread 线程退出前,即将终止的线程通过告诉DLL执行与线程相关的清理 // A thread is exiting cleanly. break; case DLL_PROCESS_DETACH: // 将一个DLL从进程的地址空间时调用// The DLL is being unmapped from the process' address space. break; } return(TRUE); // Used only for DLL_PROCESS_ATTACH}载入卸载库LoadLibrary、LoadLibraryExA、LoadPackagedLibrary、FreeLibrary、FreeLibraryAndExitThread 函数声明// 载入库HMODULE WINAPI LoadLibrary( _In_ LPCTSTR lpFileName);HMODULE LoadLibraryExA( LPCSTR lpLibFileName, HANDLE hFile, DWORD dwFlags);// 若要在通用Windows 平台(UWP)应用中加载Win32 DLL,需要调用LoadPackagedLibrary,而不是LoadLibrary 或LoadLibraryExHMODULE LoadPackagedLibrary( LPCWSTR lpwLibFileName, DWORD Reserved);// 卸载库BOOL WINAPI FreeLibrary( _In_ HMODULE hModule);// 卸载库和退出线程VOID WINAPI FreeLibraryAndExitThread( _In_ HMODULE hModule, _In_ DWORD dwExitCode);显示地链接到导出符号GetProcAddress 函数声明FARPROC GetProcAddress( HMODULE hInstDll, PCSTR pszSymbolName // 只能接受 ANSI 字符串,不能是 Unicode);DumpBin.exe 查看 DLL 信息在 VS 的开发人员命令提示符使用 DumpBin.exe 可查看 DLL 库的导出段(导出的变量、函数、类名的符号)、相对虚拟地址(RVA,relative virtual address)。

动态链接库so打包原理

动态链接库so打包原理

动态链接库so打包原理
动态链接库(Dynamic Link Library,简称DLL)是一种在Windows操作系统中常见的共享库文件格式,而在类Unix系统中通常使用的是共享对象(Shared Object,简称SO)文件。

这些库文件包含了可被程序调用的函数和资源,允许多个程序共享同一个库文件,从而节省内存和磁盘空间。

动态链接库的打包原理涉及到编译、链接和加载等多个方面。

首先,在编写程序时,开发人员会使用编程语言(如C、C++)编写源代码文件,然后通过编译器将源代码文件编译成目标文件。

接下来,编译器会将目标文件中的函数调用和外部依赖解析成符号,并生成符号表。

在链接阶段,链接器会将符号表与其他库文件进行匹配,并将程序中需要调用的函数符号与动态链接库中的函数地址进行关联,生成可执行文件。

在这个过程中,动态链接库中的函数并没有被复制到可执行文件中,而是在程序运行时动态加载。

在程序运行时,操作系统的动态链接器会根据程序中的动态链接库依赖信息,将相应的动态链接库加载到内存中,并将程序中的函数调用指向这些动态链接库中的函数地址。

这样,程序就可以在运行时动态地调用动态链接库中的函数,实现了共享和动态加载的
功能。

总的来说,动态链接库的打包原理涉及到编译、链接和加载等多个阶段,通过符号表和动态链接的方式实现了程序与动态链接库之间的关联,从而实现了动态加载和共享的功能。

windows动态库编译流程

windows动态库编译流程

windows动态库编译流程Windows动态库编译流程是将源代码转化为可执行的动态链接库(DLL)的过程。

以下是关于Windows动态库编译流程的参考内容(不包含链接)。

1. Windows动态库的编译流程通常由以下几个步骤组成:(1)预处理:预处理器会根据预编译指令处理源代码文件,例如#include指令可以将其他头文件的内容插入到当前文件中,宏定义可以在编译过程中替换为相应的内容等等。

(2)编译:编译器将预处理后的源代码文件编译成特定机器平台的目标文件,通常是一种中间代码形式,也就是目标文件(.obj)。

(3)链接:连接器将目标文件、库文件以及其他依赖项进行链接,生成最终的可执行文件或动态链接库。

连接器会解析目标文件之间的调用关系,并将函数、变量的引用解析为实际的地址。

2. 在Windows平台上,常用的编译器是微软的Visual Studio编译器。

在使用Visual Studio进行动态库编译时,可以按照以下步骤进行设置和操作:(1)新建项目:打开Visual Studio,选择“文件”→“新建”→“项目”,选择合适的项目类型(如C++库或通用Windows动态链接库等)。

根据需要进行项目的设置。

(2)编写源代码:在项目中添加源代码文件,编写动态库的实现代码。

(3)设置编译选项:右键点击项目,选择“属性”,在属性窗口中设置编译选项,如C/C++编译器的预处理器定义、头文件搜索路径、编译器警告等级、调试信息生成等。

(4)编译项目:按下F7键或选择菜单项“生成”→“生成解决方案”对项目进行编译。

编译成功后,将生成目标文件(.obj)。

(5)链接库文件:如果需要使用其他库文件,可以将这些库文件添加到项目中,并在属性窗口的链接器选项中指定库文件的路径。

(6)生成动态库:按下Ctrl+Shift+B或选择菜单项“生成”→“生成解决方案”对项目进行生成。

生成成功后,将得到最终的动态链接库文件(.dll)。

dll原理

dll原理

dll原理DLL原理动态链接库(Dynamic Link Library,简称DLL)是一种Windows 操作系统中常用的库文件,它可以被多个应用程序共享使用,从而避免了重复编写相同的代码。

本文将详细介绍DLL的原理。

一、静态链接与动态链接在介绍DLL原理之前,先来了解一下静态链接和动态链接。

1. 静态链接静态链接是指将程序所需要的库文件在编译时全部打包进可执行文件中。

这样做的好处是程序运行时不需要再加载外部库文件,因此速度较快。

但缺点也很明显,即可执行文件体积较大,在多个程序中使用相同的库时会造成重复浪费。

2. 动态链接动态链接是指在程序运行时才加载所需的库文件。

这样做的好处是节省了内存空间,并且多个程序可以共享同一个库文件。

但缺点也很明显,即运行速度较慢。

二、DLL概述1. DLL定义DLL是一个包含可由多个程序同时使用的代码和数据的库文件。

它可以被多个应用程序共享使用,从而避免了重复编写相同的代码。

2. DLL分类根据DLL所包含函数是否可以被其他应用程序调用,DLL可以分为两种类型:(1)导出函数的DLL导出函数的DLL是指将其中一些函数导出,以便其他应用程序可以调用这些函数。

这种DLL文件通常包含一组API(Application Programming Interface,应用程序编程接口)函数。

(2)内部使用的DLL内部使用的DLL是指不导出任何函数,只供当前进程中的其他模块使用。

这种DLL文件通常包含一些共享数据和实现某些功能的代码。

三、DLL加载过程1. 加载方式当一个应用程序需要调用一个DLL中的函数时,Windows操作系统会自动加载该DLL。

Windows操作系统有两种加载方式:(1)显式链接显式链接是指在编译时就将要使用的DLL文件名和需要调用的函数名写入源代码中,并在程序运行时由操作系统自动加载该DLL文件。

(2)隐式链接隐式链接是指在编译时不将要使用的DLL文件名和需要调用的函数名写入源代码中,而是在程序运行时由操作系统自动搜索并加载相应的DLL文件。

动态链接库的原理及使用

动态链接库的原理及使用

动态链接库的原理及使用动态链接库(Dynamic Link Library,简称DLL)是一种用于在Windows操作系统中共享程序代码和资源的文件格式。

DLL可以包含多个函数和数据,它们可以被多个应用程序同时使用,提供了一种更加灵活、高效的代码共享方式,使得代码的复用和维护更加方便。

DLL的原理是通过动态链接的方式将DLL文件中的函数和数据加载到内存中,然后在需要使用这些函数和数据的应用程序中进行调用。

这样做的好处是可以减少程序的体积,减少了重复代码的占用空间,提高了程序的运行效率。

DLL的使用分为两个步骤:编写和生成DLL文件,以及在应用程序中调用DLL中的函数和数据。

编写和生成DLL文件的过程通常是使用特定的开发工具或编程语言进行操作。

编写DLL文件时,需要定义导出函数,即可以被其他应用程序调用的函数。

在C/C++语言中,可以使用__declspec(dllexport)关键字来进行函数的导出声明。

生成DLL文件的过程也有多种方式,如使用编译器提供的选项进行生成,或者使用特定的构建工具进行生成。

在应用程序中调用DLL的函数和数据时,首先需要通过LoadLibrary 函数将DLL文件加载到内存中,然后使用GetProcAddress函数获取要调用的函数的地址。

获取到函数地址后,就可以像调用本地函数一样调用DLL中的函数了。

如果DLL中还有需要使用的数据,也可以通过导出的全局变量或者提供的函数来获取和使用。

除了使用LoadLibrary和GetProcAddress函数之外,Windows API 中还提供了一些使用DLL的高级函数调用方式,如使用COM组件、使用注册表等。

1.代码复用:多个应用程序可以共享同一个DLL文件,避免了代码的重复编写,提高了代码的复用性。

2.节省内存:多个应用程序共享一个DLL文件时,DLL中的代码和数据只需要在内存中加载一次,减少了内存的占用。

3.程序的灵活性:使用DLL可以实现模块化的设计和开发,提高了程序的灵活性和可维护性。

动态链接库.

动态链接库.



方法一.通过扩展关键字dllexport 与dllimport 指定 从一个动态链接库中导出一个函数可以通过如下的语句来完成 __declspec( dllexport ) void MyFunction(int i) { //动态链接库中的函数MyFunction的实现代码 } 其中__declspec是一个扩展关键字,其作用和具有一个参数的 函数类似,实际上,它与它的“参数”一起构成了一个“标志”,即 “ __declspec( dllexport) ”,该语句的含义为“出现在我后面的 函数在当前的动态链接库文件中被合法导出,外部应用程序可以使用 这个函数”。 从一个动态链接库中导入一个函数可以通过如下的语句来完成 __declspec( dllimpot ) void MyFunction(int i); __declspec(dllimpot ) 的 含 义 为 “ 出 现 在 我 后 面 的 函 数 MyFunction是从动态链接库文件中导入的函数”。
错误 1 fatal error LNK1104: 无法打开文件 “mylib.lib” MydllTester MydllTester 在运行程序之前,应将mylib.dll复制到应用程序可执行文件 所在的目录下。否则会出现图10.8所示的错误。
【例1】的运行结果
方法二.通过DEF文件指定 动态链接库DLL是通过导出函数和变量来实现代码共享的,外部程序 能通过这个导出过程来访问内部的函数和变量。 在VC 下,除了使用编译指令 dllexport 与dllimport 实现导出、导 入函数的指定外,还可以通过DLL工程中的DEF文件来实现,利用应用程 序向导生成的动态链接库中有一个和工程名同名的一个 .def 文件,例 如建立一个在 mydll.dll的动态链接库,则生成的mydll.def的主要内

WINDOWS动态链接库

WINDOWS动态链接库

WINDOWS动态链接库 第⼀代window程序员使⽤windows api进⾏编程,到了后来,微软推出MFC类库,于是,动态链接库进⾏了升级,可以在动态连接库中使⽤MFC的API,这就叫做MFC动态链接库,其中MFC动态链接库⼜分为两种,MFC规则动态链接库和MFC扩展动态链接库,两者有些不同,⼀般来说规则动态链接库封装⼀些函数,⽅法和⾃⼰对MFC⽅法的封装,⽽扩展动态链接库主要⽤于扩展MFC的控件,⽐如MFC的CLIST功能单⼀,就可以扩展成功能强⼤的表格,甚⾄可以扩展到像excel的功能. 今天说说MFC规则动态链接库,在VS中选择新建⼀个MFC DLL项⽬,就可以选择建⽴规则DLL还是扩展DLL,规则DLL没有WIN32动态链接库所有的DllMain函数,但是它包含有⼀个从CWinApp继承下来的类,theapp在DLL初始化的时候⾃动调⽤DllMain,也就是说,类似于MFC编程WinMain函数被封装起来⼀样,MFC规则动态链接库封装了DllMain. 在调⽤规则动态链接库的时候,需要注意两个⽅⾯,第⼀是:静态链接的时候,不需要DLL进⾏模块状态的切换,第⼆是动态链接的时候,⼀定不能忘了切换模块.windows程序都有着⾃⼰的资源ID,程序启动的时候,默认系统使⽤的是主线程的资源ID,程序调⽤的⼯具栏,菜单,等等资源,都与这个资源ID相关联,或者叫做资源模板.但是当DLL和调⽤程序都有着⾃⼰的资源模板的时候,主线程调⽤DLL显⽰或者使⽤某个资源的时候,如果没有切换资源ID,DLL会使⽤主线程的资源,⽽不是使⽤DLL本⾝的资源,这样就会造成程序的混乱,所以,记住⼀点,在MFC规则动态链接库中,任何函数的第⼀⾏加上AFX_MANAGE_STATE(AfxGetStaticModuleState()); 该函数类似于单⽚机的中断压栈指令,他会将原先的资源模板替换成现在正在使⽤的实例本⾝的资源模板,当程序退出这个实例的时候,⼜会因为析构函数的作⽤⾃动恢复原先的资源模板,极为⽅便. MFC规则DLL并⾮MFC应⽤程序,他所包含的CWinApp类并不包含消息循环,因为规则DLL不包括MFC的CWinApp::Run()机制,主消息泵依然由应⽤程序拥有,如果DLL⽣成⾮模态对话框,或者⾃⼰的主窗⼝框架,则应⽤程序的主消息泵必须调⽤从DLL导出来的函数来调⽤CWinApp的PreTranslateMessage()函数,将消息传送到DLL中 虽然没有DLLMain函数,但是MFC规则DLL包含另⼀个⽤于初始化DLL环境的函数InitInstance(),该函数在DLL项⽬的主APP⼊⼝类⽂件中,原型如下1 // 唯⼀的⼀个 CDinkMfcRegularDllApp 对象23 CDinkMfcRegularDllApp theApp; 456 // CDinkMfcRegularDllApp 初始化78 BOOL CDinkMfcRegularDllApp::InitInstance() 9 {10 CWinApp::InitInstance();1112 //初始化函数放在这⾥13 dllMessage.Empty();14 dllMessage.Append(TEXT("hello mfc regular dll"));1516 return TRUE;17 } 和win32 dll⼀样,规则DLL也可以导出所需的类和函数以及变量,不过有了更⽅便的⽅法,MFC定义了三个宏,帮助我们快速导出,分别是 AFX_EXT_API AFX_EXT_DATA AFX_EXT_CLASS 分别⽤于导出函数,变量和类,实际上对应的是这三个条件宏,如下#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#ifndef AFX_DATA_EXPORT#define AFX_DATA_EXPORT __declspec(dllexport)#endif#ifndef AFX_DATA_IMPORT#define AFX_DATA_IMPORT __declspec(dllimport)#endif#ifndef AFX_CLASS_EXPORT#define AFX_CLASS_EXPORT __declspec(dllexport)#endif#ifndef AFX_CLASS_IMPORT#define AFX_CLASS_IMPORT __declspec(dllimport)#endif// for global APIs#ifndef AFX_API_EXPORT#define AFX_API_EXPORT __declspec(dllexport)#endif#ifndef AFX_API_IMPORT#define AFX_API_IMPORT __declspec(dllimport)#endif 我们只需要在项⽬->属性->VC++->预处理中定义 _AFXEXT这个宏就可以了. 下⾯是⼀个实际的代码演⽰,⾸先是头⽂件#pragma once#include "stdafx.h"//动态链接库版本#define DINK_MFC_REGULAR_DLL_VERSION 0.01#define DINK_MFC_REGULAR_DLL_NAME "DinkMfcRegularDll.dll"#define DINK_MFC_REGULAR_LIB_NAME "DinkMfcRegularDll.lib"//变量EXTERN_C CString AFX_EXT_DATA dllMessage;//动态导出变量,需要三个东西,⼀个是导出函数的load时候的字符串//第⼆个转换空指针到数据指针和实际数据的两个宏定义#define DINK_REGULAR_DLL_VAR_DLLMESSAGE "dllMessage"#define MAKE_REGULAR_DLL_DLLMESSAGE_PTR(ptr) ((CString*)ptr)#define MAKE_REGULAR_DLL_DLLMESSAGE_VALUE(ptr) (*((CString*)ptr))//全局⽅法EXTERN_C void AFX_EXT_API PathAppendName(CString path,CString name,CString& dst);typedef void (*DINK_REGULAR_FUNC_PATHAPPENDNAME)(CString path,CString name,CString& dst);#define DINK_REGULAR_DLL_NAME_FUNC_PATHAPPENDNAME "PathAppendName"EXTERN_C UINT AFX_EXT_API ShowConfirmDialog(CString& class AFX_EXT_CLASS CDinkFileLogic{public://检测指定⽂件是否存在BOOL FileIsExist(CString filePath,CString fileName);//读取指定⽂件的第⼀⾏⽂本BOOL FileReadFirstLine(CString filePath,CString fileName,CString& readStr);//删除指定⽂件BOOL FileRemove(CString filePath,CString fileName);//创建指定⽂件 force表⽰⽂件要是已经存在,是否删除并覆盖,为真,删除覆盖BOOL FileCreate(CString filePath,CString fileName,BOOL force);//创建⽂件,并添加事件后缀,withTime表⽰是否添加时间,为false,则创建⽂件仅仅包含⽇期BOOL FileCreateByTime(CString filePath,CString fileName,BOOL force,BOOL withTime);//⽂件写⼊⼀⾏,isCreate 表⽰当⽂件不存在是否主动创建BOOL FileWriteLine(CString filePath,CString fileName,CString& writeStr,BOOL isCreate);//⽂件移动,moveOrCopy为真,为剪切操作为假,是拷贝操作,如果⽬标⽂件已经存在,返回失败BOOL FileMove(CString SourceFilePath,CString SourceFileName,CString dstFilePath,CString dstFileName,BOOL moveOrCopy);//⽂件移动,moveOrCopy为真,为剪切操作为假,是拷贝操作,如果⽬标⽂件已经存在,默认覆盖该⽂件BOOL FileMoveForce(CString SourceFilePath,CString SourceFileName,CString dstFilePath,CString dstFileName,BOOL moveOrCopy);protected:private:BOOL FileIsExist(CString fileFullPath);};//个⼈⽬录处理函数class AFX_EXT_CLASS CDinkDirLogic{public:{public://检测指定⽬录是否存在BOOL DirIsExist(CString dirPath);//创建指定⽬录,如果⽬录已经存在,返回OKBOOL DirCreate(CString dirPath);//创建指定⽬录,⽬录名带时间,withTime为真,带时分秒为假,仅仅年⽉⽇BOOL DirCreateByTime(CString dirPath,BOOL withTime);//移除指定⽬录,只有在⽬录为空的时候才能执⾏BOOL DirRemoveByEmpty(CString dirPath);//移除指定⽬录,不管⽬录是否为空BOOL DirRemoveNoEmpty(CString dirPath);//检测⽬标⽂件夹是否还含有⼦⽂件,返回⼦⽂件个数UINT IsDirContainFile(CString dirPath);//获取指定⽂件夹的⼦⽂件夹名和⼦⽂件夹个数UINT DirListOfDir(CString dirPath,CArray<CString>& dirArray);//获取指定⽂件夹的⼦⽂件名列表和⼦⽂件个数UINT FileListOfDir(CString dirPath,CArray<CString>& fileNameArray);//移动指定⽬录,withFile表⽰是带⽂件的移动还是仅仅移动⽬录//不会删除源⽂件夹UINT DirMove(CString sourceDirPath,CString dstDirPath,BOOL withFile);protected:private:};然后是与之对应的⽅法⽂件,数据⽂件和类⽂件,我习惯把三个⽂件分开,⽐较好维护,如下#include "stdafx.h"#include "DinkMfcRegularDllExtend.h"BOOL CDinkFileLogic::FileIsExist(CString filePath,CString fileName) {AFX_MANAGE_STATE(AfxGetModuleState());//检测⽂件是否存在CStdioFile test;CString fileFullPath;PathAppendName(filePath,fileName,fileFullPath);if(test.Open(fileFullPath,CFile::modeRead)){//可以打开test.Close();return TRUE;}else {return FALSE;}}BOOL CDinkFileLogic::FileIsExist(CString fileFullPath){AFX_MANAGE_STATE(AfxGetModuleState());CStdioFile test;if(test.Open(fileFullPath,CFile::modeRead)){//可以打开test.Close();return TRUE;}else {return FALSE;}}BOOL CDinkFileLogic::FileReadFirstLine(CString filePath,CString fileName,CString& readStr){AFX_MANAGE_STATE(AfxGetModuleState());//读取制定⽂件第⼀⾏CStdioFile test;CString fileFullPath;PathAppendName(filePath,fileName,fileFullPath);if(test.Open(fileFullPath,CStdioFile::modeRead)){//打开了readStr.Empty();test.ReadString(readStr);test.Close();return TRUE;}else {//⽂件打不开return FALSE;}}BOOL CDinkFileLogic::FileRemove(CString filePath,CString fileName){AFX_MANAGE_STATE(AfxGetModuleState());CStdioFile test;CString fileFullPath;PathAppendName(filePath,fileName,fileFullPath);CFile::Remove(fileFullPath);return TRUE;}BOOL CDinkFileLogic::FileCreate(CString filePath,CString fileName,BOOL force){AFX_MANAGE_STATE(AfxGetModuleState());CStdioFile test;CString fileFullPath;PathAppendName(filePath,fileName,fileFullPath);if(force == TRUE){//强制创建,如果存在,清除源⽂件内容if(test.Open(fileFullPath,CStdioFile::modeRead|CFile::modeCreate)){test.Close();//已经存在⽂件CFile::Remove(fileFullPath);return TRUE;}else {//创建失败return FALSE;}}else {if(test.Open(fileFullPath,CFile::modeCreate|CFile::modeRead|CFile::modeNoTruncate)){test.Close();return TRUE;}else {return FALSE;}}}BOOL CDinkFileLogic::FileCreateByTime(CString filePath,CString fileName,BOOL force,BOOL withTime){{AFX_MANAGE_STATE(AfxGetModuleState());CString timeStr;CTime time;time = time.GetCurrentTime();if(withTime == TRUE){timeStr.Append(time.Format(TEXT("%Y-%m-%d-%H-%M-%S-")));}else {timeStr.Append(time.Format(TEXT("%Y-%m-%d-")));}CString fileFullName(TEXT(""));fileFullName.Append(filePath);fileFullName.Append(TEXT("\\"));fileFullName.Append(timeStr);fileFullName.Append(fileName);CFile fileCreate;if(force == TRUE){if(fileCreate.Open(fileFullName,CFile::modeRead|CFile::modeCreate)){fileCreate.Close();return TRUE;}else {return FALSE;}}else {if(fileCreate.Open(fileFullName,CFile::modeRead|CFile::modeNoTruncate|CFile::modeCreate)){fileCreate.Close();return TRUE;}else {return FALSE;}}}BOOL CDinkFileLogic::FileWriteLine(CString filePath,CString fileName,CString& writeStr,BOOL isCreate){AFX_MANAGE_STATE(AfxGetModuleState());CString fullName;PathAppendName(filePath,fileName,fullName);CStdioFile dinkFile;if(TRUE == isCreate){//创建⽂件,如果⽂件已经存在就清空if(dinkFile.Open(fullName,CFile::modeCreate|CFile::modeReadWrite)){dinkFile.SeekToEnd();dinkFile.WriteString(writeStr);dinkFile.Flush();dinkFile.Close();return TRUE;}else {//打开⽂件失败return FALSE;}}else {//如果⽂件已经存在就打开⽽且不清空,不存在就创建if(TRUE == dinkFile.Open(fullName,CStdioFile::modeReadWrite|CFile::modeCreate|CFile::modeNoTruncate)){dinkFile.SeekToEnd();dinkFile.WriteString(writeStr+TEXT("\n"));dinkFile.Flush();dinkFile.Close();return TRUE;}else {//打开⽂件失败return FALSE;}}}BOOL CDinkFileLogic::FileMove(CString SourceFilePath,CString SourceFileName,CString dstFilePath,CString dstFileName,BOOL moveOrCopy){AFX_MANAGE_STATE(AfxGetModuleState());//⽂件移动return FALSE;}BOOL CDinkFileLogic::FileMoveForce(CString SourceFilePath,CString SourceFileName,CString dstFilePath,CString dstFileName,BOOL moveOrCopy){AFX_MANAGE_STATE(AfxGetModuleState());return FALSE;}#include "stdafx.h"#include "DinkMfcRegularDllExtend.h"#include "DinkConfirmResultDialog.h"void PathAppendName(CString path,CString name,CString& dst){AFX_MANAGE_STATE(AfxGetStaticModuleState());dst.Empty();if (path.IsEmpty()){dst.Append(TEXT(".\\"));dst.Append(name);}else {dst.Append(path);dst.Append(TEXT("\\"));dst.Append(name);}}EXTERN_C UINT AFX_EXT_API ShowConfirmDialog(CString& showString){AFX_MANAGE_STATE(AfxGetStaticModuleState());CDinkConfirmResultDialog dialog(showString);int result;result = dialog.DoModal();return result;}#include "stdafx.h"#include "DinkMfcRegularDllExtend.h"CString dllMessage; 对于资源模板,可以这样理解,应⽤程序及其调⽤的DLL每⼀个都有⼀个系统为之分配的HINSTANCE句柄,进程本⾝的模块句柄为0X400000(虚拟地址),⽽DLL的缺省句柄为0X00000000,如果程序加载多个DLL,则每个应⽤程序加载DLL的时候会对DLL进⾏重新定位. HINSTANCE句柄对于加载资源⼗分重要,如果DLL需要加载资源就需要将资源句柄指定为DLL的资源句柄,应⽤程序也可以设置⾃⼰资源句柄为DLL的资源句柄,这样可以实现加载DLL的资源,具体在MFC中,切换资源 1.DLL总调⽤AFX_MANAGE_STATE(AfxGetStaticModuleState()),主要⽤于DLL函数将应⽤程序的资源句柄切换为⾃⾝的资源句柄 2.在DLL接⼝函数调⽤HINSTANCE exeHinstance = AfxGetResourceHandle();AfxSetResourceHandle(theApp.m_instance);//....接⼝代码AfxSetResourceHandle(exeHinstance); 实现的效果和第⼀种类似 3.应⽤程序⾃⾝切换,这种⽅法可以实现exe⾃⾝加载不同的资源HINSTANCE exe_hinstance = GetModuleHandle(NULL);HINSTANCE dll_hinstance = GetModuleHandle("DLL名称");AfxSetResourceHandle(dll_hinstance);//调⽤dll函数,或者调⽤dll资源AfxSetResourceHandle(exe_hinstance);以下为静态调⽤MFC规则DLL的演⽰程序,如下//静态调⽤变量#include "..\\DinkMfcRegularDll\DinkMfcRegularDllExtend.h"#pragma comment(lib,DINK_MFC_REGULAR_LIB_NAME)void CDinkMfcRegularDllCallDlg::OnBnClickedButtonStaticShowVar(){// TODO: 在此添加控件通知处理程序代码CString showString(TEXT("load var str is : "));showString.Append(dllMessage);MessageBox(showString,TEXT("message"),MB_OK);}//静态void CDinkMfcRegularDllCallDlg::OnBnClickedButtonStaticFuncCall(){// TODO: 在此添加控件通知处理程序代码CString str1(TEXT("F:\\MFC\\DinkDll\\DinkDll\\Release"));CString str2(TEXT("DinkMfcRegularDll.dll"));CString dstStr;PathAppendName(str1,str2,dstStr);MessageBox(dstStr,TEXT("message"),MB_OK);}//静态调⽤类void CDinkMfcRegularDllCallDlg::OnBnClickedButtonStaticClassCall(){// TODO: 在此添加控件通知处理程序代码CDinkFileLogic dinkFileLogic;CString str1(TEXT("F:\\MFC\\DinkDll\\DinkDll\\Release"));CString str2(TEXT("Hello.txt"));CString dstStr;if(dinkFileLogic.FileCreate(str1,str2,FALSE)){if(dinkFileLogic.FileWriteLine(str1,str2,CString("hello world"),FALSE)){MessageBox(TEXT("write file ok"),TEXT("message"),MB_ICONINFORMATION|MB_OK);}else {MessageBox(TEXT("write file failed"),TEXT("error"),MB_ICONERROR|MB_OK);}}else {MessageBox(TEXT("file create failed"),TEXT("error"),MB_ICONERROR|MB_OK);}}void CDinkMfcRegularDllCallDlg::OnBnClickedButtonShowDialog(){// TODO: 在此添加控件通知处理程序代码UINT result;result = ShowConfirmDialog(CString("hello world"));CString confirmShowMessage(TEXT(""));confirmShowMessage.AppendFormat(TEXT("dialog return value is %d"),result);MessageBox(confirmShowMessage,TEXT("message"),MB_ICONINFORMATION|MB_OK);}以下为动态调⽤DLL//动态变量显式void CDinkMfcRegularDllCallDlg::OnBnClickedButtonDynamicShowVar(){// TODO: 在此添加控件通知处理程序代码HMODULE dllModule;CString* str;dllModule = AfxLoadLibrary(TEXT(DINK_MFC_REGULAR_DLL_NAME));if(dllModule != NULL){str = MAKE_REGULAR_DLL_DLLMESSAGE_PTR(GetProcAddress(dllModule,DINK_REGULAR_DLL_VAR_DLLMESSAGE));CString showString(TEXT("load var str is : "));showString.Append(*str);MessageBox(showString,TEXT("message"),MB_OK);AfxFreeLibrary(dllModule);}else {MessageBox(TEXT("lib load failed"),TEXT("error"),MB_ICONERROR);}}//动态调⽤函数void CDinkMfcRegularDllCallDlg::OnBnClickedButtonDynamicCallFunc(){// TODO: 在此添加控件通知处理程序代码HMODULE dllModule;DINK_REGULAR_FUNC_PATHAPPENDNAME pathAddFunc;dllModule = AfxLoadLibrary(TEXT(DINK_MFC_REGULAR_DLL_NAME));if(dllModule != NULL){pathAddFunc = (DINK_REGULAR_FUNC_PATHAPPENDNAME)(GetProcAddress(dllModule,DINK_REGULAR_DLL_NAME_FUNC_PATHAPPENDNAME));CString str1(TEXT("F:\\MFC\\DinkDll\\DinkDll\\Release"));CString str2(TEXT("DinkMfcRegularDll.dll"));CString dstStr;pathAddFunc(str1,str2,dstStr);MessageBox(dstStr,TEXT("message"),MB_OK);AfxFreeLibrary(dllModule);}else {MessageBox(TEXT("lib load failed"),TEXT("error"),MB_ICONERROR);}}MFC规则DLL,1.动态的切换应⽤程序的资源.2.能够在DLL中使⽤MFC的API但是MFC dll也不能动态的调⽤dll中的类,要使⽤类,使⽤静态调⽤. 。

动态链接库(DLL)编程深入浅出(1)

动态链接库(DLL)编程深入浅出(1)

先来阐述一下DLL(Dynamic Linkable Library)的概念,你可以简单的把DLL看成一种仓库,它提供给你一些可以直接拿来用的变量、函数或类。

在仓库的发展史上经历了“无库-静态链接库-动态链接库”的时代。

静态链接库与动态链接库都是共享代码的方式,如果采用静态链接库,则无论你愿不愿意,lib中的指令都被直接包含在最终生成的EXE文件中了。

但是若使用DLL,该DLL不必被包含在最终EXE文件中,EXE文件执行时可以“动态”地引用和卸载这个与EXE独立的DLL文件。

静态链接库和动态链接库的另外一个区别在于静态链接库中不能再包含其他的动态链接库或者静态库,而在动态链接库中还可以再包含其他的动态或静态链接库。

对动态链接库,我们还需建立如下概念:(1)DLL 的编制与具体的编程语言及编译器无关只要遵循约定的DLL接口规范和调用方式,用各种语言编写的DLL都可以相互调用。

譬如Windows提供的系统DLL(其中包括了Windows的API),在任何开发环境中都能被调用,不在乎其是Visual Basic、Visual C++还是Delphi。

(2)动态链接库随处可见我们在Windows目录下的system32文件夹中会看到kernel32.dll、user32.dll和gdi32.dll,windows的大多数API都包含在这些DLL中。

kernel32.dll中的函数主要处理内存管理和进程调度;user32.dll中的函数主要控制用户界面;gdi32.dll中的函数则负责图形方面的操作。

一般的程序员都用过类似MessageBox的函数,其实它就包含在user32.dll这个动态链接库中。

由此可见DLL对我们来说其实并不陌生。

(3)VC动态链接库的分类Visual C++支持三种DLL,它们分别是Non-MFC DLL(非MFC动态库)、MFC Regular DLL(MFC规则DLL)、MFC Extension DLL(MFC扩展DLL)。

WINDOWS动态链接库

WINDOWS动态链接库

WINDOWS动态链接库第一代window程序员使用windows api进行编程,到了后来,微软推出MFC类库,于是,动态链接库进行了升级,可以在动态连接库中使用MFC的API,这就叫做MFC动态链接库,其中MFC动态链接库又分为两种,MFC规则动态链接库和MFC扩展动态链接库,两者有些不同,一般来说规则动态链接库封装一些函数,方法和自己对MFC方法的封装,而扩展动态链接库主要用于扩展MFC的控件,比如MFC的CLIST功能单一,就可以扩展成功能强大的表格,甚至可以扩展到像excel的功能.今天说说MFC规则动态链接库,在VS中选择新建一个MFC DLL项目,就可以选择建立规则DLL还是扩展DLL,规则DLL没有WIN32动态链接库所有的DllMain函数,但是它包含有一个从CWinApp继承下来的类,theapp在DLL初始化的时候自动调用DllMain,也就是说,类似于MFC编程WinMain函数被封装起来一样,MFC规则动态链接库封装了DllMain.在调用规则动态链接库的时候,需要注意两个方面,第一是:静态链接的时候,不需要DLL进行模块状态的切换,第二是动态链接的时候,一定不能忘了切换模块.windows程序都有着自己的资源ID,程序启动的时候,默认系统使用的是主线程的资源ID,程序调用的工具栏,菜单,等等资源,都与这个资源ID相关联,或者叫做资源模板.但是当DLL和调用程序都有着自己的资源模板的时候,主线程调用DLL显示或者使用某个资源的时候,如果没有切换资源ID,DLL会使用主线程的资源,而不是使用DLL本身的资源,这样就会造成程序的混乱,所以,记住一点,在MFC规则动态链接库中,任何函数的第一行加上AFX_MANAGE_STATE(AfxGetStaticModuleState());该函数类似于单片机的中断压栈指令,他会将原先的资源模板替换成现在正在使用的实例本身的资源模板,当程序退出这个实例的时候,又会因为析构函数的作用自动恢复原先的资源模板,极为方便.MFC规则DLL并非MFC应用程序,他所包含的CWinApp类并不包含消息循环,因为规则DLL不包括MFC 的CWinApp::Run()机制,主消息泵依然由应用程序拥有,如果DLL生成非模态对话框,或者自己的主窗口框架,则应用程序的主消息泵必须调用从DLL导出来的函数来调用CWinApp的PreTranslateMessage()函数,将消息传送到DLL中虽然没有DLLMain函数,但是MFC规则DLL包含另一个用于初始化DLL环境的函数InitInstance(),该函数在DLL 项目的主APP入口类文件中,原型如下1 // 唯一的一个CDinkMfcRegularDllApp 对象23 CDinkMfcRegularDllApp theApp;456 // CDinkMfcRegularDllApp 初始化78 BOOL CDinkMfcRegularDllApp::InitInstance()9 {10 CWinApp::InitInstance();1112 //初始化函数放在这里13 dllMessage.Empty();14 dllMessage.Append(TEXT("hello mfc regular dll"));1516 return TRUE;17 }和win32 dll一样,规则DLL也可以导出所需的类和函数以及变量,不过有了更方便的方法,MFC定义了三个宏,帮助我们快速导出,分别是AFX_EXT_API AFX_EXT_DATA AFX_EXT_CLASS分别用于导出函数,变量和类,实际上对应的是这三个条件宏,如下#ifndef AFX_EXT_DATA#ifdef _AFXEXT#define AFX_EXT_CLASSAFX_CLASS_EXPORT#define AFX_EXT_APIAFX_API_EXPORT#define AFX_EXT_DATAAFX_DATA_EXPORT#define AFX_EXT_DATADEF#else#define AFX_EXT_CLASSAFX_CLASS_IMPORT#define AFX_EXT_APIAFX_API_IMPORT#define AFX_EXT_DATAAFX_DATA_IMPORT#define AFX_EXT_DATADEF#endif#endif#ifndef AFX_DATA_EXPORT#define AFX_DATA_EXPORT __declspec(dllexport) #endif#ifndef AFX_DATA_IMPORT#define AFX_DATA_IMPORT __declspec(dllimport) #endif#ifndef AFX_CLASS_EXPORT#define AFX_CLASS_EXPORT __declspec(dllexport) #endif#ifndef AFX_CLASS_IMPORT#define AFX_CLASS_IMPORT __declspec(dllimport) #endif// for global APIs#ifndef AFX_API_EXPORT#define AFX_API_EXPORT __declspec(dllexport)#endif#ifndef AFX_API_IMPORT#define AFX_API_IMPORT __declspec(dllimport)#endif我们只需要在项目-&gt;属性-&gt;VC++-&gt;预处理中定义_AFXEXT这个宏就可以了.下面是一个实际的代码演示,首先是头文件#pragma once#include "stdafx.h"//动态链接库版本#define DINK_MFC_REGULAR_DLL_VERSION 0.01#define DINK_MFC_REGULAR_DLL_NAME "DinkMfcRegularDll.dll"#define DINK_MFC_REGULAR_LIB_NAME "DinkMfcRegularDll.lib"//变量EXTERN_C CString AFX_EXT_DATA dllMessage;//动态导出变量,需要三个东西,一个是导出函数的load时候的字符串//第二个转换空指针到数据指针和实际数据的两个宏定义#define DINK_REGULAR_DLL_VAR_DLLMESSAGE "dllMessage"#define MAKE_REGULAR_DLL_DLLMESSAGE_PTR(ptr) ((CString*)ptr)#defineMAKE_REGULAR_DLL_DLLMESSAGE_V ALUE(ptr)(*((CString*)ptr))//全局方法EXTERN_C void AFX_EXT_API PathAppendName(CString path,CString name,CString&amp; dst);typedef void(*DINK_REGULAR_FUNC_PATHAPPENDNAME)(CString path,CString name,CString&amp; dst);#defineDINK_REGULAR_DLL_NAME_FUNC_PATHAPPENDNAM E "PathAppendName"EXTERN_C UINT AFX_EXT_APIShowConfirmDialog(CString&amp; showString);//存放所有需要导出的MFC规则DLL的函数,变量,类的头文件//类不能动态导出,所以相对比较好一点//个人文件处理函数class AFX_EXT_CLASS CDinkFileLogic{public://检测指定文件是否存在BOOL FileIsExist(CString filePath,CString fileName);//读取指定文件的第一行文本BOOL FileReadFirstLine(CString filePath,CString fileName,CString&amp; readStr);//删除指定文件BOOL FileRemove(CString filePath,CString fileName);//创建指定文件force表示文件要是已经存在,是否删除并覆盖,为真,删除覆盖BOOL FileCreate(CString filePath,CStringfileName,BOOL force);//创建文件,并添加事件后缀,withTime表示是否添加时间,为false,则创建文件仅仅包含日期BOOL FileCreateByTime(CString filePath,CString fileName,BOOL force,BOOL withTime);//文件写入一行,isCreate 表示当文件不存在是否主动创建BOOL FileWriteLine(CString filePath,CString fileName,CString&amp; writeStr,BOOL isCreate);//文件移动,moveOrCopy为真,为剪切操作为假,是拷贝操作,如果目标文件已经存在,返回失败BOOL FileMove(CString SourceFilePath,CString SourceFileName,CString dstFilePath,CString dstFileName,BOOL moveOrCopy);//文件移动,moveOrCopy为真,为剪切操作为假,是拷贝操作,如果目标文件已经存在,默认覆盖该文件BOOL FileMoveForce(CString SourceFilePath,CString SourceFileName,CString dstFilePath,CString dstFileName,BOOL moveOrCopy);protected:private:BOOL FileIsExist(CString fileFullPath);};//个人目录处理函数class AFX_EXT_CLASS CDinkDirLogic{public://检测指定目录是否存在BOOL DirIsExist(CString dirPath);//创建指定目录,如果目录已经存在,返回OKBOOL DirCreate(CString dirPath);//创建指定目录,目录名带时间,withTime为真,带时分秒为假,仅仅年月日BOOL DirCreateByTime(CString dirPath,BOOL withTime);//移除指定目录,只有在目录为空的时候才能执行BOOL DirRemoveByEmpty(CString dirPath);//移除指定目录,不管目录是否为空BOOL DirRemoveNoEmpty(CString dirPath);//检测目标文件夹是否还含有子文件,返回子文件个数UINT IsDirContainFile(CString dirPath);//获取指定文件夹的子文件夹名和子文件夹个数UINT DirListOfDir(CStringdirPath,CArray&lt;CString&gt;&amp; dirArray);//获取指定文件夹的子文件名列表和子文件个数UINT FileListOfDir(CStringdirPath,CArray&lt;CString&gt;&amp; fileNameArray);//移动指定目录,withFile表示是带文件的移动还是仅仅移动目录//不会删除源文件夹UINT DirMove(CString sourceDirPath,CString dstDirPath,BOOL withFile);protected:private:};然后是与之对应的方法文件,数据文件和类文件,我习惯把三个文件分开,比较好维护,如下#include "stdafx.h"#include "DinkMfcRegularDllExtend.h"BOOL CDinkFileLogic::FileIsExist(CString filePath,CString fileName){AFX_MANAGE_STATE(AfxGetModuleState());//检测文件是否存在CStdioFile test;CString fileFullPath;PathAppendName(filePath,fileName,fileFullPath);if(test.Open(fileFullPath,CFile::modeRead)){//可以打开test.Close();return TRUE;}else{return FALSE;}}BOOL CDinkFileLogic::FileIsExist(CString fileFullPath) {AFX_MANAGE_STATE(AfxGetModuleState());CStdioFile test;if(test.Open(fileFullPath,CFile::modeRead)){//可以打开test.Close();return TRUE;}else{return FALSE;}}BOOL CDinkFileLogic::FileReadFirstLine(CString filePath,CString fileName,CString&amp; readStr){AFX_MANAGE_STATE(AfxGetModuleState());//读取制定文件第一行CStdioFile test;CString fileFullPath;PathAppendName(filePath,fileName,fileFullPath);if(test.Open(fileFullPath,CStdioFile::modeRead)){//打开了readStr.Empty();test.ReadString(readStr);test.Close();return TRUE;}else{//文件打不开return FALSE;}}BOOL CDinkFileLogic::FileRemove(CString filePath,CString fileName){AFX_MANAGE_STATE(AfxGetModuleState());CStdioFile test;CString fileFullPath;PathAppendName(filePath,fileName,fileFullPath);CFile::Remove(fileFullPath);return TRUE;}BOOL CDinkFileLogic::FileCreate(CString filePath,CString fileName,BOOL force){AFX_MANAGE_STATE(AfxGetModuleState());CStdioFile test;CString fileFullPath;PathAppendName(filePath,fileName,fileFullPath);if(force == TRUE){//强制创建,如果存在,清除源文件内容if(test.Open(fileFullPath,CStdioFile::modeRead|CFile::modeCre ate)){test.Close();//已经存在文件CFile::Remove(fileFullPath);return TRUE;}else{//创建失败return FALSE;}}else{if(test.Open(fileFullPath,CFile::modeCreate|CFile::modeRead|C File::modeNoTruncate)){test.Close();return TRUE;}else{return FALSE;}}}BOOL CDinkFileLogic::FileCreateByTime(CStringfilePath,CString fileName,BOOL force,BOOL withTime){AFX_MANAGE_STATE(AfxGetModuleState());CString timeStr;CTime time;time = time.GetCurrentTime();if(withTime == TRUE){timeStr.Append(time.Format(TEXT("%Y-%m-%d-%H-%M-%S -")));}else{timeStr.Append(time.Format(TEXT("%Y-%m-%d-")));}CString fileFullName(TEXT(""));fileFullName.Append(filePath);fileFullName.Append(TEXT("\\"));fileFullName.Append(timeStr);fileFullName.Append(fileName);CFile fileCreate;if(force == TRUE){if(fileCreate.Open(fileFullName,CFile::modeRead|CFile::mode Create)){fileCreate.Close();return TRUE;}else{return FALSE;}}else{if(fileCreate.Open(fileFullName,CFile::modeRead|CFile::mode NoTruncate|CFile::modeCreate)){fileCreate.Close();return TRUE;}else{return FALSE;}}}BOOL CDinkFileLogic::FileWriteLine(CString filePath,CString fileName,CString&amp; writeStr,BOOL isCreate){AFX_MANAGE_STATE(AfxGetModuleState());CString fullName;PathAppendName(filePath,fileName,fullName);CStdioFile dinkFile;if(TRUE == isCreate){//创建文件,如果文件已经存在就清空if(dinkFile.Open(fullName,CFile::modeCreate|CFile::modeRead Write)){dinkFile.SeekToEnd();dinkFile.WriteString(writeStr);dinkFile.Flush();dinkFile.Close();return TRUE;}else{//打开文件失败return FALSE;}}else{//如果文件已经存在就打开而且不清空,不存在就创建if(TRUE ==dinkFile.Open(fullName,CStdioFile::modeReadWrite|CFile::mo deCreate|CFile::modeNoTruncate)){dinkFile.SeekToEnd();dinkFile.WriteString(writeStr+TEXT("\n"));dinkFile.Flush();dinkFile.Close();return TRUE;}else{//打开文件失败return FALSE;}}}BOOL CDinkFileLogic::FileMove(CString SourceFilePath,CString SourceFileName,CString dstFilePath,CString dstFileName,BOOL moveOrCopy) {AFX_MANAGE_STATE(AfxGetModuleState());//文件移动return FALSE;}BOOL CDinkFileLogic::FileMoveForce(CString SourceFilePath,CString SourceFileName,CString dstFilePath,CString dstFileName,BOOL moveOrCopy) {AFX_MANAGE_STATE(AfxGetModuleState());return FALSE;}#include "stdafx.h"#include "DinkMfcRegularDllExtend.h"#include "DinkConfirmResultDialog.h"void PathAppendName(CString path,CStringname,CString&amp; dst){AFX_MANAGE_STATE(AfxGetStaticModuleState());dst.Empty();if (path.IsEmpty()){dst.Append(TEXT(".\\"));dst.Append(name);}else{dst.Append(path);dst.Append(TEXT("\\"));dst.Append(name);}}EXTERN_C UINT AFX_EXT_API ShowConfirmDialog(CString&amp; showString){AFX_MANAGE_STATE(AfxGetStaticModuleState());CDinkConfirmResultDialog dialog(showString);int result;result = dialog.DoModal();return result;}#include "stdafx.h"#include "DinkMfcRegularDllExtend.h"CString dllMessage;对于资源模板,可以这样理解,应用程序及其调用的DLL 每一个都有一个系统为之分配的HINSTANCE句柄,进程本身的模块句柄为0X400000(虚拟地址),而DLL的缺省句柄为0X00000000,如果程序加载多个DLL,则每个DLL都有一个不同的HINSSTANCE,应用程序加载DLL的时候会对DLL进行重新定位.HINSTANCE句柄对于加载资源十分重要,如果DLL需要加载资源就需要将资源句柄指定为DLL的资源句柄,应用程序也可以设置自己资源句柄为DLL的资源句柄,这样可以实现加载DLL的资源,具体在MFC中,切换资源句柄的方法有以下几种1.DLL总调用AFX_MANAGE_STATE(AfxGetStaticModuleState()),主要用于DLL函数将应用程序的资源句柄切换为自身的资源句柄2.在DLL接口函数调用HINSTANCE exeHinstance = AfxGetResourceHandle(); AfxSetResourceHandle(theApp.m_instance);//....接口代码AfxSetResourceHandle(exeHinstance);实现的效果和第一种类似3.应用程序自身切换,这种方法可以实现exe自身加载不同的资源HINSTANCE exe_hinstance = GetModuleHandle(NULL); HINSTANCE dll_hinstance = GetModuleHandle("DLL名称"); AfxSetResourceHandle(dll_hinstance);//调用dll函数,或者调用dll资源AfxSetResourceHandle(exe_hinstance);以下为静态调用MFC规则DLL的演示程序,如下//静态调用变量#include "..\\DinkMfcRegularDll\DinkMfcRegularDllExtend.h" #pragma comment(lib,DINK_MFC_REGULAR_LIB_NAME)voidCDinkMfcRegularDllCallDlg::OnBnClickedButtonStaticShowV ar(){// TODO: 在此添加控件通知处理程序代码CString showString(TEXT("load var str is : "));showString.Append(dllMessage);MessageBox(showString,TEXT("message"),MB_OK);}//静态voidCDinkMfcRegularDllCallDlg::OnBnClickedButtonStaticFuncC all(){// TODO: 在此添加控件通知处理程序代码CStringstr1(TEXT("F:\\MFC\\DinkDll\\DinkDll\\Release"));CString str2(TEXT("DinkMfcRegularDll.dll"));CString dstStr;PathAppendName(str1,str2,dstStr);MessageBox(dstStr,TEXT("message"),MB_OK);}//静态调用类voidCDinkMfcRegularDllCallDlg::OnBnClickedButtonStaticClassC all(){// TODO: 在此添加控件通知处理程序代码CDinkFileLogic dinkFileLogic;CStringstr1(TEXT("F:\\MFC\\DinkDll\\DinkDll\\Release"));CString str2(TEXT("Hello.txt"));CString dstStr;if(dinkFileLogic.FileCreate(str1,str2,FALSE)){if(dinkFileLogic.FileWriteLine(str1,str2,CString("hello world"),FALSE)){MessageBox(TEXT("write fileok"),TEXT("message"),MB_ICONINFORMATION|MB_OK);}else{MessageBox(TEXT("write filefailed"),TEXT("error"),MB_ICONERROR|MB_OK);}}else{MessageBox(TEXT("file createfailed"),TEXT("error"),MB_ICONERROR|MB_OK);}}voidCDinkMfcRegularDllCallDlg::OnBnClickedButtonShowDialog (){// TODO: 在此添加控件通知处理程序代码UINT result;result = ShowConfirmDialog(CString("hello world"));CString confirmShowMessage(TEXT(""));confirmShowMessage.AppendFormat(TEXT("dialog return value is %d"),result);MessageBox(confirmShowMessage,TEXT("message"),MB_IC ONINFORMATION|MB_OK);}以下为动态调用DLL//动态变量显式voidCDinkMfcRegularDllCallDlg::OnBnClickedButtonDynamicSho wVar(){// TODO: 在此添加控件通知处理程序代码HMODULE dllModule;CString* str;dllModule =AfxLoadLibrary(TEXT(DINK_MFC_REGULAR_DLL_NAM E));if(dllModule != NULL){str =MAKE_REGULAR_DLL_DLLMESSAGE_PTR(GetProcAddr ess(dllModule,DINK_REGULAR_DLL_V AR_DLLMESSAGE));CString showString(TEXT("load var str is : "));showString.Append(*str);MessageBox(showString,TEXT("message"),MB_OK);AfxFreeLibrary(dllModule);}else{MessageBox(TEXT("lib loadfailed"),TEXT("error"),MB_ICONERROR);}}//动态调用函数voidCDinkMfcRegularDllCallDlg::OnBnClickedButtonDynamicCal lFunc(){// TODO: 在此添加控件通知处理程序代码HMODULE dllModule;DINK_REGULAR_FUNC_PATHAPPENDNAMEpathAddFunc;dllModule =AfxLoadLibrary(TEXT(DINK_MFC_REGULAR_DLL_NAM E));if(dllModule != NULL){pathAddFunc =(DINK_REGULAR_FUNC_PATHAPPENDNAME)(GetProcA ddress(dllModule,DINK_REGULAR_DLL_NAME_FUNC_PA THAPPENDNAME));CStringstr1(TEXT("F:\\MFC\\DinkDll\\DinkDll\\Release"));CString str2(TEXT("DinkMfcRegularDll.dll"));CString dstStr;pathAddFunc(str1,str2,dstStr);MessageBox(dstStr,TEXT("message"),MB_OK);AfxFreeLibrary(dllModule);}else{MessageBox(TEXT("lib loadfailed"),TEXT("error"),MB_ICONERROR);}}MFC规则DLL,1.动态的切换应用程序的资源.2.能够在DLL 中使用MFC的API但是MFC dll也不能动态的调用dll中的类,要使用类,使用静态调用.。

DLL的原理范文

DLL的原理范文

DLL的原理范文动态链接库(Dynamic Link Library,DLL)是一种在Windows操作系统中用于存储被多个应用程序共享的程序代码和数据的可执行文件。

它们经常用于存储程序的功能模块,可以在需要时被不同的应用程序动态链接调用,从而提高了程序的复用性和可维护性。

在本文中,我们将探讨DLL的原理和工作机制。

一、DLL的原理DLL是一种包含可执行代码、数据和资源的文件,它可以由多个程序共享并在运行时被动态地加载到内存中。

DLL的原理主要是基于动态链接技术,其中包含两个主要概念:静态链接和动态链接。

1.静态链接在编译程序时,编译器会将程序中所需的函数和库文件的代码复制到可执行文件中,这个过程就称为静态链接。

这样做的好处是可以将程序和其所依赖的库文件打包成一个独立的可执行文件,使得程序的移植性更强。

但是这样也会导致可执行文件的体积变得庞大,而且每次更新库文件时都需要重新编译整个程序。

2.动态链接相比于静态链接,动态链接的原理是将程序所需的函数和数据与库文件分开存储,当程序需要调用库文件中的函数或者数据时,通过动态链接器将库文件加载到内存中,然后将程序中的函数和库文件中的函数进行链接,从而实现函数的调用。

这种方式可以减小程序的体积,提高程序的运行效率,并且使得程序可以灵活地调用不同版本的库文件。

二、DLL的工作机制DLL的工作机制主要包括DLL的加载、链接和卸载三个过程。

1.DLL的加载当程序开始运行时,操作系统会根据程序中指定的DLL文件路径,通过动态链接器将DLL文件加载到内存中。

在加载DLL文件时,动态链接器会解析DLL文件的导出表,获取DLL中所包含的函数以及函数的地址,然后将这些信息保存到程序的内存中,以备程序需要调用DLL中的函数时进行链接。

2.DLL的链接在程序需要调用DLL中的函数时,动态链接器会根据函数名在程序的内存中查找DLL导出表中对应函数的地址,并将程序中的函数调用指向DLL中的函数地址,从而实现函数的调用。

dynamic 解析

dynamic 解析

dynamic 解析【实用版】目录1.动态链接库(DLL)的概念与作用2.动态链接库的优点3.动态链接库的缺点4.动态链接库的创建与使用5.动态链接库的维护与管理正文动态链接库(Dynamic Link Library,简称 DLL)是 Windows 操作系统中一种可重用的代码模块,它包含了可由多个应用程序共享的函数和数据。

DLL 的出现大大提高了软件开发和运行的效率,使得开发者能够更加专注于功能的实现,而不必关心底层的代码组织和管理。

动态链接库具有以下优点:1.代码共享:DLL 允许多个应用程序共享相同的代码模块,有效减少了内存占用和磁盘空间。

同时,当 DLL 中的函数或数据发生变化时,只需修改一处,即可在所有使用该 DLL 的应用程序中生效,方便了代码的维护。

2.模块化:通过将功能划分为独立的 DLL,开发者可以按照需求将各个模块组合使用,提高了开发效率和灵活性。

3.延迟加载:DLL 可以在运行时动态加载,这意味着只有当应用程序实际需要时,才会加载相应的 DLL。

这样可以减少应用程序的启动时间,提高运行效率。

尽管动态链接库带来了诸多好处,但同时也存在一定的缺点:1.依赖问题:由于多个应用程序共享同一个 DLL,当 DLL 发生版本更新时,可能导致旧版本应用程序无法正常运行。

开发者需要确保 DLL 的版本兼容性,以避免潜在的依赖问题。

2.安全隐患:由于 DLL 可以被多个应用程序共享,恶意代码有可能通过篡改 DLL 来攻击其他应用程序。

因此,开发者需要对 DLL 进行严格的安全审查和保护。

创建和使用动态链接库较为简单。

首先,使用 C 或 C++等编程语言编写 DLL 源代码,然后使用链接器将源代码编译为 DLL 文件。

在应用程序中,通过指定 DLL 文件的路径,即可加载并调用其中的函数和数据。

动态链接库的维护和管理同样重要。

开发者需要定期检查 DLL 的代码和数据,确保其正确性和安全性。

同时,还需关注 DLL 的版本更新,及时修复潜在的问题,以满足不断变化的应用需求。

windows查找依赖库原则

windows查找依赖库原则

windows查找依赖库原则
在Windows 操作系统中,查找动态链接库(DLL)的原则涉及到一系列搜索路径和规则,系统会按照特定的顺序查找并加载DLL。

以下是Windows 查找依赖库的一般原则:
当前工作目录(Current Working Directory):
Windows 将首先在应用程序的当前工作目录中查找DLL。

这通常是执行应用程序的可执行文件所在的目录。

系统目录(System Directory):
如果DLL 不在当前工作目录中,Windows 将搜索系统目录(通常是C:\Windows\System32)。

这包括一些系统级的DLL。

Windows 目录:
如果DLL 仍然未找到,系统会搜索Windows 目录(通常是C:\Windows)。

应用程序目录(Application Directory):
如果DLL 不在当前工作目录、系统目录或Windows 目录中,系统会在应用程序的目录中查找。

这是指应用程序的可执行文件所在的目录。

PATH 环境变量:
最后,系统会搜索系统的PATH 环境变量中指定的目录。

PATH 环境变量包含一组目录路径,系统会按照这些路径的顺序查找DLL。

在这个搜索路径中,Windows 将按照上述顺序查找依赖库。

一旦找到匹配的DLL,系统将加载并执行相应的代码。

需要注意的是,这种搜索路径的机制使得Windows 在查找依赖库时具有一定的灵活性,但也可能导致一些问题,比如版本冲突、不明确的DLL 来源等。

在开发和部署应用程序时,确保DLL 的位置和
版本是可控的,以避免潜在的问题。

全面分析Linux动态库和windows动态库

全面分析Linux动态库和windows动态库

全面分析Linux动态库和windows动态库本文这里分析Linux动态库和windows动态库通常采用的动态库调用方法以及程序编制方式。

动态库的目的减少程序的大小,节省空间,提高效率,具有很高的灵活性。

采用动态库技术对于升级软件版本更加容易,动态库里面的函数不是执行程序本身的一部分,而是根据执行需要按需载入,其执行代码可以同时在多个程序中共享。

windows动态库技术动态链接库是实现Windows应用程序共享资源、节省内存空间、提高使用效率的一个重要技术手段。

常见的动态库包含外部函数和资源,也有一些动态库只包含资源,如Windows字体资源文件,称之为资源动态链接库。

通常动态库以.dll,.drv、.fon 等作为后缀。

相应的windows静态库通常以.lib结尾,Windows自己就将一些主要的系统功能以动态库模块的形式实现。

Windows动态库在运行时被系统加载到进程的虚拟空间中,使用从调用进程的虚拟地址空间分配的内存,成为调用进程的一部分。

DLL也只能被该进程的线程所访问。

DLL的句柄可以被调用进程使用;调用进程的句柄可以被DLL使用。

DLL 模块中包含各种导出函数,用于向外界提供服务。

DLL可以有自己的数据段,但没有自己的堆栈,使用与调用它的应用程序相同的堆栈模式;一个DLL在内存中只有一个实例;DLL实现了代码封装性;DLL的编制与具体的编程语言及编译器无关,可以通过DLL来实现混合语言编程。

DLL函数中的代码所创建的任何对象(包括变量)都归调用它的线程或进程所有。

根据调用方式的不同,对动态库的调用可分为静态调用方式和动态调用方式。

(1)静态调用,也称为隐式调用,由编译系统完成对DLL的加载和应用程序结束时DLL卸载的编码(Windows系统负责对DLL调用次数的计数),调用方式简单,能够满足通常的要求。

通常采用的调用方式是把产生动态连接库时产生的.LIB 文件加入到应用程序的工程中,想使用DLL中的函数时,只须在源文件中声明一下。

dll 原理

dll 原理

dll 原理DLL(动态链接库)是一种在程序运行时被动态加载的文件,它包含了可在不同程序之间共享的代码和数据。

DLL的使用可以提高代码的重用性,降低程序的内存占用和可执行文件的体积。

DLL原理的核心是动态链接。

当一个程序需要调用DLL中的函数时,系统会在程序运行时将DLL加载到内存中,并将DLL中的函数地址与程序中的函数调用进行关联。

这样,程序就可以通过调用函数的地址来直接访问DLL中的功能。

在DLL原理中,存在两种类型的DLL:静态链接的DLL和动态链接的DLL。

静态链接的DLL是在链接时将DLL的代码和数据嵌入到可执行文件中的,程序在运行时无需加载DLL,直接引用DLL中的功能。

这种方式虽然简单,但是会造成可执行文件的体积增大,并且无法在运行时更新DLL。

动态链接的DLL是在运行时被加载的。

程序在运行时通过调用Windows系统提供的函数来加载DLL,然后通过函数的地址来访问DLL中的功能。

这种方式使得DLL可以独立于程序进行更新和升级,可以实现热插拔功能。

在DLL的原理中,Windows系统提供了一些函数供程序进行DLL的加载和调用。

其中最常用的是LoadLibrary函数和GetProcAddress函数。

LoadLibrary函数用于加载DLL文件。

程序可以通过指定DLL文件的路径来加载DLL,加载成功后,LoadLibrary函数返回一个指向DLL模块的句柄。

此后,可以使用这个句柄来引用DLL中的函数。

GetProcAddress函数用于获取DLL中的函数地址。

程序通过指定DLL模块的句柄和函数名称来获取函数地址,然后通过函数地址来调用DLL中的函数。

这样,在程序运行时就可以动态地选择和调用DLL中的函数。

除了LoadLibrary和GetProcAddress函数,Windows系统还提供了一些其他的函数供程序进行DLL的加载和卸载,如FreeLibrary函数可以用来卸载DLL。

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

二、C和C++在编译期间对函数名的修改
这里可以做一个简单的试验,创建一个dll项目,其中只包含两个函数,一个是返回两个数的和,另一个返回两个数的差。

其代码如下:
TEST.H
TEST.cpp
分别更改EXPORT和调用协定可以获取6个结果,及
[__declspec,__stdcall]、[extern"C"__declspec,__stdcall]、
[__declspec,__cdecl]、[extern"C"__declspec,__cdecl]、
[__declspec,__fastcall]、[extern"C"__declspec,__fastcall]
extern"C",是要求在使用C++编译器的时候,采用C风格为函数命名,通常会在函数名前加“_”、在函数名后面添加“@参数长度”,例如上例中的AddNum,被以C风格编译后变为_AddNum@8;
extern_stdcall.gif
这个定义为extern"C"__stdcall
_stdcall.gif
这个定义为__stdcall
此外调用方式也会对编译后生成的函数名有影响。

不同的调用方式产生的结果如下:
_cdecl.gif
extern_cdecl.gif
extern_fastcall.gif
_fastcall.gif
所以在生成dll时应考虑到函数名称的变化。

三、生成通用性库
为了使其他语言能够很容易的使用dll动态库,在编译过程中需要保持函数名称不变,这时候可以通过模块定义文件(.def文件),对导出的函数和变量进行定义
定义格式如下:
LIBRARY库名称.dll
EXPORTS
导出名=函数名@Ordinal NONAME/PRIVATE
这里用一个例子进行说明(VS2010):
首先创建一个C++下的空项目,取名TEST,然后右键单击项目资源管理器中的项目,选择属性,在打开的属性对话框->常规中,将配置类型改为“动态库(dll)”
在项目的源文件文件夹下创建一个cpp文件,输入如下代码:
然后在项目中新建一个“模块定义文件(.def)”,写入如下代码:
然后单击编译即可。

编译完成后可以查看Lib和dll中导出的函数有什么不同,
lib
注意:被定义为private的函数没有被导出,说明从引用链接库是不允许访问private 修饰的函数
dll
注意:被定义为NONAME的函数,在动态库中是无法通过函数名访问的,但可以通过Ordinal访问。

一般动态链接库会提供三个文件,
一个是动态链接库中导出函数声明的头文件,及.h文件;
一个是引用链接库文件,此文件用于确定代码中函数调用的来源,此文件中保存了同名dll文件中的导出函数的连接信息,扩展名为.lib;
一个是动态库文件,这个文件是函数所在文件也是包含所有代码的文件,扩展名为.dll
使用方式
动态链接库的使用方式分为两种,一种是静态连接,一种是动态连接;
动态连接在知道其导出函数的情况下,可以只用一个.dll文件即可,这里先不介绍动态连接的方法,先介绍静态连接的方法。

静态连接是在程序开发期间进行连接的,在开发期间如果不需要运行程序,而只是达到编译程序则完全用不到.dll文件;静态连接有两种方式,一种是通过IDE给项目配置的属性中进行引用链接库文件的导入,另一种是通过预处理命令#pragma comment(lib, PCSTR)导入,下面分别介绍:
一、通过IDE静态导入
1、首先将动态库提供的头文件导入到项目头文件目录下,并将头文件引入要调用dll 中函数的c或cpp文件中(注意:向项目中导入头文件时先将头文件复制到项目的文件目录下,然后在项目头文件目录上单击右键添加现有项);
2、将引用链接库文件(.lib)拷贝到项目根目录,然后右键单击项目->属性->连接器->输入->附加依赖项,然后单击编辑,在打开的编辑对话框中将引用链接库文件名输入,单击确定。

这时项目已经能够成功编译,但是无法运行,会提示找不到动态链接库dll,这时需要将dll 文件放入到exe所在的文件夹下,及Debug或Release文件夹。

到这里,就完成了动态链接库静态引用的全部过程。

二、通过#pragma comment(lib,PCSTR)引用
其他步骤几乎没有区别,只是在第二步不需要通过IDE将lib文件导入,而是在要使用dll库函数的cpp文件中,或其头文件中输入#pragma comment(lib,PCSTR),即可
注:在一些第三方动态库提供的时候,头文件可能不止一个(一个头文件中引用其它头文件),动态库也可能不止一个(动态库中引用了其它动态库);当不能确定引用哪些个头文件和动态库时,可以设置包含目录和库目录,如下图:
前面已经介绍过了动态链接库的创建和通过引用链接库(lib)的方式使用动态链接库;在这里就介绍一下如何在代码中动态加载链接库。

在代码中动态加载和使用动态库主要使用的是系统提供的两个API
LoadLibrary(PCSTR)和GetProcAddress(HMODE,PCSTR)
这种使用库的方式只需要dll文件,而不像引用链接库那样需要.h和.lib文件。

只需要将dll库文件拷贝到运行目录。

GetProcAddress(HMODE,PCSTR),返回的是动态库中函数的指针,所以在使用前应该用typedef定义要调用的函数的函数指针类型;此外,GetProcAddress()的第二个参数有两种选择,一种是直接传入导出函数名称(注意:是导出函数名称,而不是源代码中定义的函数
名称,在编译过程中会发生改变的;可以用dumpbin/EXPORTS test.dll查看导出函数)。

另外一种是通过导出列表中的Ordinal序号,也就是在def中定义的“@编号”,将其强制转换成PCSTR类型,传入即可。

下面是对如下的动态库进行使用的例子:
dll
应用代码:
#undef UNICODE
#include<Windows.h>
#include<stdio.h>
typedef int(__stdcall*pfnNum)(CONST int,CONST int);//定义函数指针类型
int main(int argc,char**agrs)
{
HINSTANCE hLibrary;
pfnNum pfnNumber;
int iNum1=9;
int iNum2=3;
int iRes=0;
hLibrary=LoadLibrary("TEST.dll");
if(!hLibrary)
{
printf("LoadLibrary TEST.dll Faild!\n");
return-1;
}
if((pfnNumber=(pfnNum)GetProcAddress(hLibrary,"AddNum"))==NULL)
{
printf("GetProcAddress AddNum Faild!\n");
return-1;
}
else
{
iRes=pfnNumber(iNum1,iNum2);
printf("%d+%d=%d",iNum1,iNum2,iRes);
}
if((pfnNumber=(pfnNum)GetProcAddress(hLibrary,"OrdNumber"))==NULL)
{
printf("GetProcAddress AddNum Faild!\n");
return-1;
}
else
{
iRes=pfnNumber(iNum1,iNum2);
printf("%d+%d=%d\n",iNum1,iNum2,iRes);
}
if((pfnNumber=(pfnNum)GetProcAddress(hLibrary,(PCSTR)3))==NULL)//由于定义了NONAME,所以采用Ordinal值进行调用
{
printf("GetProcAddress AddNum Faild!\n");
return-1;
}
else
{
iRes=pfnNumber(iNum1,iNum2);
printf("%d+%d=%d\n",iNum1,iNum2,iRes);
}
if((pfnNumber=(pfnNum)GetProcAddress(hLibrary,"HubNum"))==NULL)
{
printf("GetProcAddress AddNum Faild!\n");
return-1;
}
else
{
iRes=pfnNumber(iNum1,iNum2);
printf("%d+%d=%d\n",iNum1,iNum2,iRes);
}
return0;
}。

相关文档
最新文档