Raymond Chen 2008年08月08日
如果从 DLL_PROCESS_ATTACH 返回 FALSE,是否会得到 DLL_PROCESS_DETACH?
如果你在DLL_PROCESS_ATTACH
中返回FALSE
,你会收到DLL_PROCESS_DETACH
吗?
是的。
不是。
...
是的。
这三个答案都是正确的,取决于问题的具体情况。
从内核的角度来看,答案很简单:是的。如果一个DLL的入口点对DLL_PROCESS_ATTACH
通知返回FALSE
,它将接收到DLL_PROCESS_DETACH
通知。
然而,大多数C和C++程序不使用原始的DLL入口点。相反,它们使用C运行时入口点,其名称可能类似于DllMainCRTStartup
。这个入口点函数会执行管理工作,以管理C运行时库,并调用你的入口点(你可能已经将其命名为DllMain
),看看你有什么想法。
如果你在2002年之前编译了你的程序,并且你的DllMain
函数在响应DLL_PROCESS_ATTACH
通知时返回FALSE
,那么C运行时代码会说,“哦,好吧,我猜我实际上并没有运行”,然后关闭自己。当内核用DLL_PROCESS_DETACH
通知调用C运行时入口点时,C运行时会说,“哦,我已经关闭了,谢谢你的询问”,并立即返回,这意味着你的入口点没有用DLL_PROCESS_DETACH
通知被调用。换句话说,如果你在2002年之前编写了你的程序,答案是不。
大约在2002年或2003年的某个时候,C运行时团队改变了行为。如果你的DllMain
函数在响应DLL_PROCESS_ATTACH
通知时返回FALSE
,你仍然会收到DLL_PROCESS_DETACH
通知。换句话说,如果你在大约2002年或2003年之后编写了你的程序,那么答案是是的。为什么要改变?也许他们想要更接近内核行为,也许他们认为他们之前的行为是一个错误。你得问他们。
这对作为程序员的你意味着什么?有些人可能会看这个并得出结论,“嗯,现在我知道每个特定场景是如何工作的,我可以依靠知道我所在的场景产生的行为。例如,因为我使用的是Visual Studio 2008,答案是是的。”但我认为这是错误的结论,因为你通常无法完全控制你的程序是如何编译和链接的。你可能与其他项目共享你的代码,而那个项目可能不知道你依赖于特定版本的Visual Studio 2008的行为;他们会用Borland C++版本5.5编译你的程序,现在你的程序就微妙地坏了。我的建议是编写你的DllMain
函数,使其无论在哪种场景中使用都能正确工作。(而且,因为你的DllMain
函数本来就不应该做太多事情,所以这应该不会带来太大负担。)
备注
我不知道Borland C++版本5.5在从DllMain
返回FALSE
时的行为是什么。我不想去研究一个行为与Visual Studio 2008不同的编译器,所以我随机选了一个。我有50/50的机会是正确的。