6

DLL 中的函数是否可以卸载 DLL?我需要这样做,以确保 DLL 未在使用中,然后写入 DLL 的文件。

4

4 回答 4

20

据我了解,它可以完成并且有时是必须完成的(例如,在通过 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 的代码仍在使用它,并且此模块句柄确实不是您来管理的。

于 2013-11-29T07:05:39.957 回答
7

当 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;
于 2013-03-22T02:37:37.483 回答
0

我不认为它会起作用。当代码在不再有效的内存位置运行时,从外部使用句柄调用 FreeLibrary(将从 DLL 外部的区域调用 LoadLibrary)。

即使这是可能的,但它闻起来像是一个糟糕的设计。也许您想制作一些更新程序或类似的东西。多解释一下您期望的结果是什么。从内部卸载 DLL 不是可行的方法。

于 2010-08-04T22:11:32.283 回答
0

如果您询问是否可以从 DLL 本身的代码中安全地卸载/取消映射进程中加载​​的 DLL,答案是否定的 - 没有真正安全的方法可以做到这一点。

这样想:卸载 DLL 是通过使用 FreeLibrary() 减少它的引用计数来完成的。问题当然是一旦 DLL 的引用计数达到零,模块就会被取消映射。这意味着 DLL 中调用 FreeLibrary() 的代码消失了。

即使您可以这样做,您仍然需要确保没有其他线程执行从 DLL 导出的任何函数。

于 2010-08-04T22:12:06.847 回答