简述
- 在
Windows中,DLL(动态链接库)可以请求操作系统卸载自己,但这样做是有风险的 - 要确保在
DLL被卸载后不再访问任何DLL内部的资源或函数
FreeLibrary
- 如果在
test.dll的某个函数里面,获取到test.dll的句柄后,调用FreeLibrary释放了test.dll,会发生什么? - 当你调用
FreeLibrary,它会减少DLL的引用计数。如果引用计数达到0,系统会开始卸载该DLL- 这意味着该DLL的代码、数据和其他资源都将被从内存中删除。
- 如果在
FreeLibrary之后还有代码需要执行,那么这些代码所在的内存位置可能已经被操作系统回收或已被标记为无效- 尝试在已经卸载的内存位置执行代码会导致未定义的行为,通常这会导致程序崩溃
解决
- 可以创建一个新线程来释放
DLL,并在该线程中调用FreeLibraryAndExitThread - 这样,新线程会释放
DLL并安全地退出,而不会影响DLL中其他正在运行的代码
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 |
#include <windows.h> BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved) { switch (ul_reason_for_call) { case DLL_PROCESS_ATTACH: break; case DLL_THREAD_ATTACH: break; case DLL_THREAD_DETACH: break; case DLL_PROCESS_DETACH: break; } return TRUE; } extern "C" __declspec(dllexport) void UnloadMyself() { // 获取当前DLL的句柄 HMODULE hModule = NULL; GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, (LPCTSTR)UnloadMyself, &hModule); // 创建一个新线程来卸载该DLL CloseHandle(CreateThread(NULL, 0, [](LPVOID lpModule) -> DWORD { Sleep(100); // 为调用方留出一些时间来完成其工作 FreeLibraryAndExitThread((HMODULE)lpModule, 0); return 0; }, hModule, 0, NULL)); } |
注意
- 应该让调用
DLL的程序负责加载和卸载DLL - 如果确实需要在
DLL内部释放自己,确保在调用FreeLibrary后不再执行任何代码
为什么要新起线程
- 不会阻塞原先线程
- 通过在新的线程中设定了等待时间,确保原始线程在
DLL卸载之前有更多的时间完成其工作
声明:本文为原创文章,版权归Aet所有,欢迎分享本文,转载请保留出处!
你可能也喜欢
- ♥ Windows IOCP07/22
- ♥ Windows 核心编程 _ 用户模式:线程同步二07/16
- ♥ Windbg关于死锁的简单调试分析总结09/13
- ♥ Dump分析:未捕获的异常,查看内存相关命令03/25
- ♥ Windows 高级调试 _ 内存破坏03/21
- ♥ 关于异常的捕获和dump文件的生成07/05