FreeLibrary vs隐式卸载DLL

时间:2010-04-28 04:45:19

标签: c++ winapi dll

我已经实现了一个包含DllMain()入口函数的DLL: -

BOOL APIENTRY DllMain( HMODULE hModule,
  DWORD  ul_reason_for_call,
  LPVOID lpReserved
  )
{
    case DLL_PROCESS_ATTACH:
    /* here im doing file memory mapped through CreateFileMapping() API 
       and using it through MapViewOfFile() API
       storing some data structure in the file mapped area */
    ...
    case DLL_THREAD_ATTACH:
    ...
    case DLL_THREAD_DETACH:
    ...
    case DLL_PROCESS_DETACH:
    /* Here unmapping first through UnmapViewOfFile() API
       then tries to access the stroed data structure which is illegal 
       as we have already closed the file mapping
       This is the buggy code. The order should be first access the mapped memory 
       region and then unmap it */
       cout <<" some message"<<endl;
    ...

}

不幸的是我在DLL_PROCESS_DETACH案例中犯了一个错误并访问了非法的memorey(访问冲突)。

我制作了一个示例程序,它使用LoadLibrary()函数加载库,使用库函数,最后调用FreeLibrary()并返回。

当我执行此程序时,我没有收到任何错误消息。 但是,如果我删除FreeLibrary(),那么DLL_PROCESS_DETACH案例是隐式执行的,这次它给出了错误对话框,提到存在访问冲突。

为什么调用FreeLibrary()可以抑制此错误?或内部它处理此异常? 建议的方式。

更新:我已经添加了ATTACH和DETACH的详细信息。可能它会帮助我不清楚所观察到的行为。 使用FreeLibrary()调用,我没有收到任何错误消息,但没有显示cout消息。它似乎也崩溃了,但没有被证实。 但是,如果我删除FreeLibrary(),在这种情况下,DLL_PROCESS_DETACH情况将被隐式执行并提供访问冲突对话框。 理想情况下,在前一种情况下,它应该显示错误。所以我猜测FreeLibrary()会抑制此访问冲突错误。

2 个答案:

答案 0 :(得分:2)

The MSDN page for DllMain有一个引用可能有助于解释发生在你身上的事情。

  

当处理DLL_PROCESS_DETACH时,只有在动态卸载DLL时(lpReserved参数为NULL),DLL才应释放堆内存等资源。如果进程正在终止(lpvReserved参数为非NULL),则除当前线程之外的进程中的所有线程已经退出或已通过调用ExitProcess函数显式终止,这可能会留下一些进程资源,例如堆处于不一致的状态。在这种情况下,DLL清理资源是不安全的。相反,DLL应该允许操作系统回收内存。

因此,如果您正在调用FreeLibrary,那么它基本上是一个干净的关闭。一切都处于有效状态。 Dll创建的任何线程仍然存在。它的所有记忆都还在。

但是如果你只是关闭程序(并且不要调用FreeLibrary)那么它更像是紧急关闭(想想崩溃)。您的Dll会被操作系统而不是应用程序通知。如果这是崩溃的结果,那么希望内存仍然有效并不是一个好主意。无论如何,堆栈已经消失了。

所以我的猜测是你遇到了这个问题,因为非自由库的卸载方式不同。

答案 1 :(得分:0)

在调用FreeLibrary时,程序的其他部分都映射到您的虚拟内存空间。如果在程序的其他部分已经关闭之后自动释放了你的dll,那么程序的更少部分仍然会映射到你的虚拟内存空间。

因此,当您调用FreeLibrary时,DLL_PROCESS_DETACH案例中的错误可能会访问程序其他部分正在使用的内存。