为啥不从入口点函数调用 FreeLibrary?

Posted

技术标签:

【中文标题】为啥不从入口点函数调用 FreeLibrary?【英文标题】:Why not call FreeLibrary from entry point function?为什么不从入口点函数调用 FreeLibrary? 【发布时间】:2010-12-26 13:22:29 【问题描述】:

我正在编写一个需要多次动态调用单独的 DLL 的 DLL。我想保持被调用者加载,然后在卸载我的 DLL 时将其卸载。但根据微软的说法,那是bad idea。

入口点函数应该只 执行简单的初始化任务 并且不应调用任何其他 DLL 加载或终止功能。为了 例如,在入口点函数中, 你不应该直接或间接地 调用 LoadLibrary 函数或 LoadLibraryEx 函数。此外, 你不应该调用 FreeLibrary 进程运行时的函数 终止。

这是有问题的代码。有人能解释一下为什么我不应该从我的 DLL 入口点调用 LoadLibrary 和 FreeLibrary 吗?

BOOL APIENTRY DllMain( HANDLE hModule, 
                       DWORD  ul_reason_for_call, 
                       LPVOID lpReserved
                     )

switch (ul_reason_for_call) 
    case DLL_PROCESS_DETACH :
            if (hLogLib != NULL) FreeLibrary(hLogLib);
            break;
    
    return TRUE;

【问题讨论】:

你怎么知道DLL还没有被卸载? @Anon:我不知道。事实上,我什至不知道它曾经被加载过。但如果它已加载但尚未卸载,我想卸载它。 听起来您应该静态链接到另一个 DLL,而不是尝试动态加载它。 @Remy,如果可以的话,我会的。 DLL 的路径在编译时不可用。 也许压力在于“您不应该在进程终止时调用 FreeLibrary 函数。”也就是说,当进程终止时不做任何事情,也许目标是尽快退出以节省计算资源。 【参考方案1】:

我想我找到了the answer。

入口点函数应该 只执行简单的初始化或 终止任务。它不能调用 LoadLibrary 或 LoadLibraryEx 函数(或调用的函数 这些功能),因为这可能 在 DLL 中创建依赖循环 加载顺序。这可能会导致 DLL 在系统有之前被使用 执行其初始化代码。 同样,入口点函数 不得调用 FreeLibrary 函数 (或调用 FreeLibrary 的函数) 在进程终止期间,因为 这可能会导致使用 DLL 系统执行后 终止代码。

【讨论】:

现在还不清楚,库的代码在被终止和释放后会用到什么?我假设一个人只释放一个之前加载的库......并且终止代码仅在此 FreeLibrary 调用释放对该 DLL 的最后引用时运行。【参考方案2】:

您不能从入口点调用 LoadLibrary,因为 DllMain 函数在操作系统加载程序锁内运行,任何重新获取该加载程序锁的尝试(例如,通过调用 LoadLibrary)都会导致死锁。

【讨论】:

但是 FreeLibrary 呢?这会导致什么样的问题?【参考方案3】:

不要在 DLLMain 内做任何后果。严重地。调用 FreeLibrary 更糟糕,因为它只会有时死锁,如果碰巧你的 free 将 refcount 减为零并且库实际上已被释放。

【讨论】:

以上是关于为啥不从入口点函数调用 FreeLibrary?的主要内容,如果未能解决你的问题,请参考以下文章

动态载入DLL所需要的三个函数详解(LoadLibrary,GetProcAddress,FreeLibrary)

C#函数复习

为啥数组会引起nvlink警告:入口函数的堆栈大小不能静态确定

为啥不从谷歌地图标记上的点击事件中调用 navigator.getCurrentPosition (function (position) )

为啥我不能在 C# 应用程序中使用泛型类型作为入口点?

调用 FreeLibrary 时可能出现死锁