如果卸载加载它的DLL,是否会删除DLL?

时间:2009-03-05 16:46:05

标签: windows winapi dll

采用标准Windows应用程序。它使用LoadLibrary加载DLL来调用其中的函数(我们称之为DLL_A)。该函数加载另一个DLL(我们称之为DLL_B)。应用程序现在使用FreeLibrary卸载DLL_A DLL,因为它不再需要它。

问题是: DLL_B是否仍在内存中并加载?

这是我可以依赖的东西,还是没有文件记录?

4 个答案:

答案 0 :(得分:11)

没有。 DLL_B将不会被卸载。 LoadLibrary()进行的DLL_A调用将增加DLL_B的加载计数。由于FreeLibrary()没有相应的DLL_B调用,因此引用计数不会归零。

来自LoadLibrary()docs:

  

系统维护每个进程   所有已加载模块的引用计数。   调用LoadLibrary会增加   引用计数。打电话给   FreeLibrary或   FreeLibraryAndExitThread函数   减少引用计数。该   系统卸载模块时   引用计数达到零或何时   该过程终止(无论如何   引用计数)。

答案 1 :(得分:3)

在这种情况下你会遇到手柄泄漏:

Program -Load> Dll A 
          -Load> Dll B 
        -Unload> Dll A

卸载的模块不会隐式执行代码来卸载它加载的模块。

由于没有执行代码来减少引用计数,因此永远不会卸载模块B.

以下是加载/卸载dll的规则:

  • 每次调用LoadLibrary和LoadLibraryEx都会增加该模块的引用计数。这仅在调用进程的上下文中,而不是跨进程边界。
  • 每次调用FreeLibrary或FreeLibraryAndExitThread都会减少引用次数。
  • 当引用计数达到0时,将被卸载。
  • 当Windows发现您的程序已关闭时,将卸载任何泄漏的已卸载模块。
  • 根据您的操作,DllCanUnloadNow可能对您有用。

仍然在内存中仍然加载:

当参考值达到0时,无法保证模块将在某个时间从内存中释放。但是当参考计数达到0时,您应该将模块视为已卸载。

停止卸载DLL:

要强制卸载DLL,您可以尝试

  • 系统使用DLL_PROCESS_DETACH标志调用DllMain。您可以尝试通过某种阻止操作不从此返回。
  • 您可以尝试从DLL中调用您想要无法卸载的LoadLibrary。 (自我负载)

修改:

您提到您的目标是将代码绑定到正在运行的程序中,并且您希望故意泄漏句柄。

没关系,但是如果你经常运行这个操作,可能会导致源程序崩溃,因为会使用太多的句柄,或者最终会使用太多的内存。

您可以从DllMain返回FALSE以阻止它被加载,这样您就不会浪费内存。当fdwReason是DLL_PROCESS_ATTACH时,你这样做。你可以read more about it here

如果您尝试模拟DLL并添加自己的额外功能,则需要实现源DLL实现的所有函数,并将每个调用委托回源DLL。

答案 2 :(得分:1)

阅读备注部分以获取详细说明。

需要注意的关键是:

  

系统维护每个已加载模块的每进程引用计数

并进一步向下

  

当模块的引用计数达到零或进程终止时,系统从进程的地址空间卸载模块

来自MSDN

  

释放加载的动态链接库(DLL)模块,并在必要时减少其引用计数。当引用计数达到零时,模块将从调用进程的地址空间中卸载,并且句柄不再有效。

答案 3 :(得分:1)

Windows中的DLL是引用计数的。当A被卸载时,你将A上的引用计数递减,如果它达到零,它将卸载,并且(假设代码中没有错误)减少B上的引用计数。如果B上的引用计数变为零,则它将被卸载。可能DLL C在B上有引用,卸载A不会卸载B。