关于dll的一些事



前一阵 有点忙。断了写博客的习惯。这习惯断了就要养回来。。。。。最近在搞DLL,以下是转载内容。。

转载地址:http://www.aichengxu.com/article/C++/15300_4.html

另外再推荐一个日志,对于动态链接库写的好详细。http://www.cnblogs.com/kzloser/archive/2012/11/13/2765748.html#b3_0


关于dll的一些事,有需要的朋友可以参考下。


以下是我自己对dll的一些疑问:

1.dll里面有个dllmain函数,那么在什么情况下依次进入以下四个分支?

case DLL_PROCESS_ATTACH:
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:

2.是否可以对同一个dll进行重复加载多次?那样做的效果是什么?即loadlibrary函数的特性

3.在不同进程里面加载的dll句柄handle是否相同?

4.加载到进程的dll什么时候被释放,是否可以对同一个dll释放多次?

5.dll里面的全局变量在什么时候初始化?

6.dll里面嵌套了其它dll时,加载和释放的顺序是什么。

7.dll里面循环嵌套(即A模块加载B模块的同时,B模块又会自动加载A模块)可以么?如果可以那么加载和释放的顺序是什么?

8.如果既可以对多个dll加载多次也可以对多个dll释放多次那么,两者的次数是否必须相等?

9.dll在第一个次使用它的时候加载到内存(动态加载的方式),那么在什么情况下从内存中彻底删除?

以下是本人亲测一下午的总结

注意:本次所有测试都是在win7平台vs2008上面测的,主要测试类型是动态加载的方式,没有涉及到静态加载时会是怎样的效果(太累了,眼睛花),

有兴趣的朋友可以自己测试一下。


1.dll里面有个dllmain函数,那么在什么情况下依次进入以下四个分支?

case DLL_PROCESS_ATTACH:
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:

case DLL_PROCESS_DETACH:

答:在进程第一次加载dll的时候回进入DLL_PROCESS_ATTACH分支,有且仅有一次;

在进程正常结束或者明确使用FreeLibrary达到彻底引用减少到0的时候会进入case DLL_PROCESS_DETACH分支,有且仅有一次。

在进程或者当前进程加载的dll里面如果创建了新的线程,那么在该线程第一次得到cpu时钟的时候会进入所有dll的case DLL_THREAD_ATTACH分支,由于可以 创建多个线程,因此可能有多次。

在线程函数执行完毕正常返回(即return或者exitthread)时会进入当前进程所加载的所有dll的case DLL_THREAD_DETACH,有0次或者多次进入的可能。

2.是否可以对同一个dll进行重复加载多次?那样做的效果是什么?即loadlibrary函数的特性

答:完全可以用LoadLibrary多次加载同一个dll,实际上只有第一次是真正的加载,也会进入dllmain函数的DLL_PROCESS_ATTACH分支,后续使用LoadLibrary由于探测到进程地址空间中已经加载了该dll,因此只返回第一次加载成功的相同句柄,根本不会进入dllmain函数的DLL_PROCESS_ATTACH,因此后续只是对计数器加1。

3.在不同进程里面加载的dll句柄handle是否相同?(本人标注,对于本条保留意见

答:完全相同。

4.加载到进程的dll什么时候被释放,是否可以对同一个dll释放多次?

答:可以释放多次,每次都对引用计数减1,档计数为0的时候就从进程中卸掉该dll,此时会进入dllmain函数的case DLL_PROCESS_DETACH:分支,并且 Freelibrary会在这次返回false,后面再继续调用Freelibrary也会返回false。

5.dll里面的全局变量在什么时候初始化?

答:dll里的全局变量在dll第一次加载到进程里面时初始化,早于dllmain函数的执行。

6.dll里面嵌套了其它dll时,加载和释放的顺序是什么?

答:如果明确用的Loadlibrary加载,那么顺序会严格按照LoadLibrary出现的顺序加载的。释放的顺序也是先加载谁就先释放谁。

7.dll里面循环嵌套(即A模块加载B模块的同时,B模块又会自动加载A模块)可以么?如果可以那么加载和释放的顺序是什么?

答:假设进程加载模块A.dll,A.dll里面在全局加载B.dll,也就是HMODULE hB=LoadLibraryA("B.dll")写在函数外面。同时B.dll里面又返回来加载A.dll,也是在全局写了如下的加载语句:HMODULE hA=LoadLibraryA("A.dll")这样就会导致循环加载A.dll时B会先初始化全局变量,从而执行HMODULE hB=LoadLibraryA("B.dll"),就会加载B,但是B又会初始化它自己的全局变量,导致HMODULE hA=LoadLibraryA("A.dll")被执行。这样就会导致循环加载,但实际上情况是这样的,加载顺序是A->B->A,只不过最后一次因为已经加载了所以不会重复加载,但进入dllmain函数的顺序是先进入B.dll的dllmain,然后再进入A.dll的dllmain。释放顺序先进入B.dll的dllmain然后再进入A.dll的dllmain,因为这个是真正的执行顺序。

另外,这种情况下DLL_THREAD_ATTACH:和DLL_THREAD_DETACH:的顺序进出的顺序是这样的:线程第一次切换时先进入A.dll的DLL_THREAD_ATTACH再进入B.dll的DLL_THREAD_ATTACH,线程函数运行完毕时先进入B.dll的DLL_THREAD_DETACH再进入A.dll的DLL_THREAD_DETACH。这和进程分支的情况正好相反。

8.如果既可以对多个dll加载多次也可以对多个dll释放多次那么,两者的次数是否必须相等?

答:可以不相等,但释放的次数必须大于等于加载的次数,否则不会真正卸载该dll,但会等待进程结束的时候释放。

9.dll在第一个次使用它的时候加载到内存(动态加载的方式),那么在什么情况下从内存中彻底删除?

答:多个进程可以引用同一个dll,每隔进程里面维护着对dll的引用计数,但进程内的引用计数只能用来决定是否从进程中卸载该dll。但dll真正是否能够从内存中删去,是靠另外一种计数N来维护的,那就是只要有一个进程加载了此dll且未卸载掉,那么N就会加1,一旦某个进程卸载掉了此dll,N就会减1,只有N减少到0的时候,操作系统才会从内存中将此dll测定删掉。

结语:相信有这些疑问的不止我一个人,希望能帮到同样有疑问的朋友,以上都是我亲自动手测试的,限于水品有限,若有错误请即刻指出,我会尽快修改,以免误导他人。


  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值