2010-04-28 74 views
0

我已经实现包括的DllMain()入口函数的DLL: -FreeLibrary则VS隐含卸载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()会抑制这个访问冲突错误。

回答

0

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

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

+0

让我们假设在DLL_PROCESS_DETACH中我释放了内存然后访问它。所以你说的不是这里的情况。 – Adil 2010-04-28 05:18:17

+1

也许你应该发布你的实际代码,所以我们不必猜测? – 2010-04-28 05:30:55

+0

添加完整的源代码将会太大。我在帖子中添加了一些细节。请参阅,希望它有助于我的怀疑。 – Adil 2010-05-05 18:24:35

2

The MSDN page for DllMain有一句话可能有助于解释发生了什么事。

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

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

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

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

+0

你说的是真的,但在我的情况下,它仍然不清楚。我在帖子中为ATTACH和DETACH案例添加了一些细节。请参阅,希望它有助于我的怀疑。在DETACH情况下,无论OS是通知DETACH情况还是应用程序本身,都会执行案例代码。事情是非法的内存访问将发生在这两种情况。 – Adil 2010-05-05 18:26:38

+0

我只是看着你的改变。你能告诉我访问违规发生在哪一行吗?虽然,即使你告诉我机会,我的回应将是“你正在访问的那个对象不再有效的记忆。” (很明显,这就是访问冲突):D我在稍后阅读了一篇很棒的文章:它简化了文件的影子副本(有点像Word一样)。这样,如果你的应用程序崩溃或功率消失,事情不会丢失。但更重要的是,它可以让你只是崩溃。事情会因设计而优雅。希望这可以帮助。 – ProgramMax 2010-05-05 18:58:25

+0

Butmy问题仍然没有回答:)在代码执行方面没有区别,正如我提到的那样,我做了unmap,然后尝试访问非法的文件映射内存。在FreeLibrary()的情况下,访问内存位置之后的下一条语句不会被执行,并且会自动执行程序。在隐式调用DETACH的情况下,出现访问冲突错误对话框,然后我才意识到。所以我的观点是为什么相同的对话框没有出现在FreeLibrary()调用中。你不能说,即使在取消映射后,内存访问在这种情况下是合法的:) – Adil 2010-05-06 12:32:27