让DLL卸载自身 -- FreeLibraryAndExitThread()

实际问题:

DLL是MFC的DLL, 我在这个DLL的初始化函数中创建了一个对话框窗口, 如何在dll中操作实现结束dll当前的线程和释放掉dll. 
比如在窗口(模态对话框)关闭后结束线程, 释放dll.
kernel32.dll里有个函数叫FreeLibraryAndExitThread
就是专门给你做这种事情用的:
正常情况下你调用FreeLibrary来释放当前执行的代码所在的DLL会导致FreeLibrary返回以后无法继续执行之后的代码(DLL已经释放了)
而这个函数会在FreeLibrary之后结束当前线程,这个操作的代码在kernel32.dll中,所以不存在上述问题

今天的问题是:有没有可能让一个 DLL 自己卸载自己?

这个问题可以分成两个部分:
1.卸载一个 DLL。
2.卸载 DLL 的代码应该是放在 DLL之中的。

当然,如果不考虑后果的话,这个代码并不难写,如下:

    #include <Windows.h>  
      
    HMODULE g_hDll = NULL;  
      
    DWORD WINAPI UnloadProc(PVOID param)  
    {  
        MessageBox(NULL, TEXT("Press ok to unload me."),  
            TEXT("MsgBox in dll"), MB_OK);  
        FreeLibrary(g_hDll);  
        // oops!  
        return 0;  
    }  
      
    BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, PVOID lpvReserved)  
    {  
        if (DLL_PROCESS_ATTACH == fdwReason)  
        {  
            g_hDll = (HMODULE)hinstDLL;  
            HANDLE hThread = CreateThread(NULL, 0, UnloadProc, NULL, 0, NULL);  
            CloseHandle(hThread);  
        }  
        return TRUE;  
    }  

简单说明一下:在 DllMain 初始化的时候保存 DLL 的实例句柄(即模块句柄)供 FreeLibrary 调用,然后开启一个线程,在适当的时机调用 FreeLibrary 销毁 DLL。

但是,如果实际运行起来的话,我们会遇到一个很实际的问题:在 FreeLibrary 之后,该 DLL 的地址空间就不再可用了,但这时 EIP 指针仍然会指向 FreeLibrary 的下面一句,于是程序崩溃。

所幸,Win32 提供了另外的一个 API——FreeLibraryAndExitThread,这个函数能够在销毁 DLL 之后直接调用 ExitThread,这样一来 EIP 指针就不会指向非法的地址了。因此,我们只需要把 FreeLibrary 的一句替换为:

FreeLibraryAndExitThread(g_hDll, 0);  

这样就可以了。

实际测试一下,在 DLL 被加载后,July 的模块视图显示了这个被加载的 DLL。

在内存视图中检查模块句柄指向的内容,证明该 DLL 的确被加载了。

让DLL卸载自身 -- FreeLibraryAndExitThread()_第1张图片

FreeLibraryAndExitThread 调用后,再查看该模块句柄指向的内存,该地址已不再可用,销毁成功。

让DLL卸载自身 -- FreeLibraryAndExitThread()_第2张图片


参考:

http://blog.csdn.net/titilima/article/details/4103495

参考2:

http://www.clxp.net.cn/article/994.html

你可能感兴趣的:(让DLL卸载自身 -- FreeLibraryAndExitThread())