【问题标题】:Can we call FreeLibrary from ExitInstance我们可以从 ExitInstance 调用 FreeLibrary
【发布时间】:2012-12-12 03:03:12
【问题描述】:

从 MSDN 文档中可以看出,我们不应该在 DllMain 入口点函数中调用 LoadLibrary/FreeLibrary。

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

我的问题是:我们可以从 ExitInstance() 调用 FreeLibrary 吗? 例如:

Test.exe - 主要可执行文件

HINSTANCE hDllMFC = LoadLibrary(L"TestApp.dll");
if (hDllMFC != NULL)
{
    FreeLibrary(hDllMFC);
}

while unload the hDllMFC, the call stack looks like:

TestApp.dll!CTestAppApp::ExitInstance() Line 42 C++
TestApp.dll!InternalDllMain() Line 155  C++
TestApp.dll!DllMain() Line 272  C++
TestApp.dll!__DllMainCRTStartup() Line 512  C
TestApp.dll!_DllMainCRTStartup() Line 477   C
ntdll.dll!LdrpUnloadDll()   Unknown
ntdll.dll!LdrUnloadDll()    Unknown
KernelBase.dll!FreeLibrary()    Unknown
Test.exe!wmain() Line 17    C++

TestApp.dll - 动态链接到 MFC 的常规 DLL

CTestApp theApp;
HINSTANCE hDllResource = NULL;

BOOL CTestApp::InitInstance()
{
    hDllResource = ::LoadLibrary(L"TestApp_Resource.dll");

    return CWinApp::InitInstance();
}

int CTestApp::ExitInstance()
{
    ::FreeLibrary(hDllResource);

    return CWinApp::ExitInstance();
}

TestApp_Resource.dll - 常规 DLL、资源

...

我认为我们不应该,但是从 CWinApp::ExitInstance() 的实现中,我们可以看到,它也在试图卸载资源 dll。这是否意味着我们可以在 ExitIntance() 中调用 FreeLibrary?

int CWinApp::ExitInstance()
{
  //... 

 if (m_hLangResourceDLL != NULL)
  {
    ::FreeLibrary(m_hLangResourceDLL);
    m_hLangResourceDLL = NULL;
  }
  //...
}

我还发现了一个文档,它确认在 Win95 中从 ExitInstance 调用 FreeLibrary 时存在错误。

BUG:从 ExitInstance 调用 AfxFreeLibrary 时断言 http://support.microsoft.com/kb/187684

状态:Microsoft 已确认这是 Windows 95 中的错误。我们是 研究此错误并将在此处发布新信息 可用的 Microsoft 知识库。

【问题讨论】:

  • 调用 ExitInstance() 时释放 DLL 毫无意义。无论如何,当进程终止时,DLL 将在几毫秒后自动卸载。
  • 由于 CWinApp 是在主可执行文件中声明的,因此不会从 DllMain 调用其 ExitInstance(还有其他原因,因为可执行文件没有 DllMain)。因此,这个问题没有实际意义。
  • @RaymondChen,谢谢,我已经完善了我的问题,即 TestApp.dll 是动态链接到 MFC 的常规 DLL,因此调用 ExitInstance() 以响应 InternalDllMain 中的 DLL_PROCESS_DETACH 消息。跨度>
  • 卸载TestApp.dll的调用栈已经贴在问题内了。

标签: windows dll mfc


【解决方案1】:

如果实际上 ExitInstance 是从 DllMain 调用的(由堆栈跟踪确认),则适用于 DllMain 的所有规则,包括禁止以递归方式加载或卸载其他 DLL。 (请注意,将您的 CWinApp 放入 DLL 是非常不寻常的,MFC 可能还有其他问题,例如知识库文章中提到的问题。并不是说有或没有任何问题潜伏,而是添加一个额外的注释小心。)

【讨论】:

  • Win8 中 FreeLibrary 的行为似乎发生了变化,导致 MFC 模块状态混乱,如果您可以查看 MSDN 论坛中的相关问题here,不胜感激
猜你喜欢
  • 2012-01-28
  • 1970-01-01
  • 2013-02-01
  • 1970-01-01
  • 2011-11-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多