DLL 中的函数是否可以卸载 DLL?我需要这样做,以确保 DLL 未在使用中,然后写入 DLL 的文件。
4 回答
据我了解,它可以完成并且有时是必须完成的(例如,在通过 CreateRemoteThread 和其他方法注入 dll 的情况下)。所以,
FreeLibraryAndExitThread(hModule, 0)
会做到这一点。
另一方面,调用
FreeLibrary(hModule)
不会在这里做 - 来自 MSDN:“如果他们分别调用 FreeLibrary 和 ExitThread,则会存在竞争条件。可以在调用 ExitThread 之前卸载库。” 需要说明的是,ExitThread 除了从线程函数返回之外还做了一些记账。
所有这一切都假设您的 Dll 通过从加载的 Dll 内部调用LoadLibrary来获取 hModule 本身,或者更确切地说,通过从加载的 Dll 内部调用以下函数:
GetModuleHandleEx
(
GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS,
(LPCTSTR)DllMain,
&hModule
)
这会增加 Dll 的引用计数,因此您知道,如果您稍后使用该句柄释放库并且该库确实已卸载,那么您拥有对它的最后引用。
如果您在DLL_PROCESS_ATTACH期间跳过增加 Dll 的引用计数并仅从DllMain
的参数中获取 hModule,那么您不应调用FreeLibraryAndExitThread,因为加载 Dll 的代码仍在使用它,并且此模块句柄确实不是您来管理的。
当 dll 完成它的工作时使用它:
CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)FreeLibrary, &__ImageBase, 0, NULL);
// terminate if dll run in a separate thread ExitThread(0);
// or just return out the dll
__ImageBase 是你的 dll 的 PE 头结构:
EXTERN_C IMAGE_DOS_HEADER __ImageBase;
我不认为它会起作用。当代码在不再有效的内存位置运行时,从外部使用句柄调用 FreeLibrary(将从 DLL 外部的区域调用 LoadLibrary)。
即使这是可能的,但它闻起来像是一个糟糕的设计。也许您想制作一些更新程序或类似的东西。多解释一下您期望的结果是什么。从内部卸载 DLL 不是可行的方法。
如果您询问是否可以从 DLL 本身的代码中安全地卸载/取消映射进程中加载的 DLL,答案是否定的 - 没有真正安全的方法可以做到这一点。
这样想:卸载 DLL 是通过使用 FreeLibrary() 减少它的引用计数来完成的。问题当然是一旦 DLL 的引用计数达到零,模块就会被取消映射。这意味着 DLL 中调用 FreeLibrary() 的代码消失了。
即使您可以这样做,您仍然需要确保没有其他线程执行从 DLL 导出的任何函数。