Dll(动态链接库)的加载分为2种:
静态加载动态加载
首先来看一个Dll的例子:
上面3张图分别是main.cpp, Test.h以及Test.cpp。其编译连接后生成了一个名为Sample.dll以及对应的Sample.lib导入库。
静态加载是通过如下几种方式使用:
首先可以通过#pragma comment语句来静态使用dll
或者可以通过在项目属性中的附加依赖项添加对应的导入库来静态使用
这种情况下就无需#pragma comment语句了
最后一种方法是更加直接, 直接把对应的lib添加到工程内部即可, 这样既无需#pragma comment语句也不需要在属性内添加导入库路径
可以看到这3种方法最重要的点在于让VS能够找到导入库的位置。
上述静态加载dll的三种方法都需要导入库(*.lib)参与,实际上还是比较麻烦的,而动态加载dll则没有这种要求
动态加载是通过LoadLibrary和GetProcAddress来实现的
这里不解释如何实现,这里来说一下其中可能会碰到让人感到头疼的问题:
首先来看一下利用动态加载使用dll导出函数的例子:
看上去没有什么问题,但是调试过程中却发现了GetProcAddress获取对应导出函数地址没有成功
现在利用Winhex打开sample.dll查看, 发现了Test()导出函数的命名发生了变化
将这个新名字作为参数传入GetProcAddress后发现获取对应导出函数地址成功
所以之前利用GetProcAddress()来获取Test()函数地址没有成功是由于没有获取正确的函数名称。由于C和C++的编译器都具有对应的名称粉碎机制。即会把对应函数名修改成一种特殊格式(不同编译器的名称粉碎规则都不同, 即使都是C编译器,可能不同公司出产的C编译器名称粉碎规则也不同, 所以无需深究)。
为了解决这个问题,可以将dll的导出函数声明前添加一个extern "C",这就告诉了编译器用C语言的方式编译
这样就能利用原导出函数名称成功获取对应地址了
看完这个后再来DllMain,其中有4个标志
分别解释下
DLL_PROCESS_ATTACH是Dll被载入对应进程的虚拟地址空间时会被调用
DLL_PROCESS_DETACH时DLL从对应进程虚拟地址空间内被卸载时会被调用
DLL_THREAD_ATTACH是DLL所在进程创建了新线程会被调用
DLL_THREAD_DETACH是DLL所在进程有线程终结时被调用
DllMain的返回值是布尔类型。一般都是返回TRUE。假设说返回FALSE会怎么样?
1. 如果DLL是静态加载的情况DllMain返回FALSE会导致DLL_PROCESS_DETACH被触发并且会出现0xC0000142错误
2. 如果DLL是动态加载的情况DllMain返回FALSE会导致DLL_PROCESS_DETACH被触发并LoadLibrary会返回NULL。
注意这种返回FALSE导致的问题只有在DLL_PROCESS_ATTACH选项被触发时才会出现,其他3种选项返回FALSE会被忽略。
(完)



