游戏辅助工具开发教程-从入门到精通之A3_14篇
作者:Figo
本篇讲解动态链接库。
动态链接库俗称DLL,为什么叫做动态链接呢?因为我们内存资源有限,为了节约硬件资源,系统把内部提供的API统一加载一份,当程序需要调用API时,如果此时内存空间没有该API则追寻该API相关DLL信息并加载到内存中,如果此时又有其他程序需要调用该API,系统就不再加载,而是通过一种机制使这2个程序共用同一份代码,整个过程成为动态链接。也即需要的时候才动态加载,你可以理解为U盘,需要使用时就加载,不需要拔出即可。
下面我们来看一个例子:


Demo实现了一个很简单的例子,就是调用DLL中预先定义的函数,然后结束。
不要把DLL想成多么神秘的新事物,有句谚语说得好:太阳底下无新事。DLL长相和EXE看起来有些不同,其实有些exe、各种ocx和ime为后缀的文件也是DLL。当接触到一个新的事物时,我们要问自己的第一个问题是,它的逻辑是怎样的?放在此处需要首先知道的是,DLL的架构是什么。包括以后要接触到的驱动模型也是相似的学习方式。下面来看DLL的逻辑图:

知道了结构和需要的文件,我们开始动手编写代码:

DllMain函数是调用dll时的入口函数,可以理解为dll中的WinMain。需要介绍的函数入口参数如下:
HANDLE hModule
这个参数存储DLL的基地址,WinMain入口参数种HINSTANCE hInstance存储的是EXE的基地址。获取该值的方法最好在入口函数被调用时保存,因为之后可能就没有其它简易方法获取了。在DLL中使用GetModuleHandle及类似API获取的地址是加载该DLL进程的句柄(此处句柄就是运行时的基地址)。
DWORD ul_reason_for_call
这个参数有4个可选值,表示DLL被加载的原因,依次如下:
DLL_PROCESS_ATTACH//进程加载或调用LoadLibrary函数
DLL_THREAD_ATTACH//当前进程创建了新的线程或调用LoadLibrary函数
DLL_THREAD_DETACH//线程终止
DLL_PROCESS_DETACH//进程终止或调用FreeLibrary函数
入口点函数结束后就开始导出函数的定义:

上面是源文件部分,紧接着是导出表文件部分:

这里是头文件定义:

我们的DLL只是导出一个Box函数,实现部分在源文件中。DLL文件写好之后,编译运行是看不到效果的,我们需要另外写一个加载DLL的程序来加载。加载的常用方法有2种:一种是编译期加载;一种是运行期加载。我们下面要介绍的方法是运行期加载。实现如下:

这里需要介绍的函数有三个:
1、LoadLibrary(LPCTSTR lpFileName)
该函数加载指定的可执行模块(可以是.exe或.dll):可以是指定路径;亦可为直接给出的文件名(我们上面的代码是此种情况)。对于指定路径的话,路径格式要如下:C:\\MyDllDef\\demo.dll,使用反斜杠\;直接给出名字的话,系统路径寻找dll次序如下:
1)、应用程序的当前路径
2)、系统目录(可使用GetSystemDirectory函数获取)
3)、16位系统路径(属于为了兼容之前系统保留之用,在NT下用不到)
4)、Windows目录(可使用GetWindowsDirectory函数获取)
5)、环境变量中给出的目录。
该函数执行成功则返回指定加载模块的句柄,否则返回NULL。
2、FreeLibrary(HMODULE hModule)
当不使用或退出时,需要调用该函数释放资源,入口参数为LoadLibrary获取的模块句柄。
3、GetProcAddress(HMODULE hModule, LPCSTR lpProcName)
该函数用于获取lpProcName指定函数名函数的地址,第一个参数是LoadLibrary获取的模块句柄,第二个是函数名称。
这里需要强调的是,加载dll时候一定要检查指针是否为NULL,否则或出现不可预料的错误。至此,dll以及它如何使用的大致流程就完成了:点击下载源码。

讲的浅显易懂,太好了。
不错,我又来顶啦。
五笔打字真爽 ^ ^
顶顶,感谢老师
老师,建立DLL文件是选用An empty DLL project,cpp文件和头文件,以及def 文件都是手动写的么?
@mpgsf
正确:)
多谢老师赐教,
我刚开了一个辅助开发QQ群,好让大家相互交流
群号:113793738