分享

关于dll的一些事

 quasiceo 2017-06-09

关于dll的一些事

分类: vc  |  标签: c++,dll,dllmain,进程,线程  |  作者: springontime 相关  |  发布日期 : 2014-05-26  |  热度 : 130°

           以下是我自己对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测定删掉。

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

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多