6

从 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 知识库中发布新信息,因为它可用。

4

1 回答 1

5

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

于 2012-12-27T02:19:36.737 回答