持续化更新的视状态,在DLL中使用托管扩展
2006-07-20 11:43:22 来源:WEB开发网- 应用程序加载你的 DLL (LoadLibrary);
- LoadLibrary 调用 _DllMainCRTStartup;
- _DllMainCRTStartup 调用 _CRT_INIT;
- _CRT_INIT 调用静态构造函数;
- _DllMainCRTStartup 调用 DllMain;
- DllMain 进行更多的初始化;
- 应用程序调用 DLL 函数;
如果你使用 MFC,你甚至都不知道 DllMain 的存在,因为 MFC 为你提供了这个入口。在 MFC 中,一切都是从 CWinApp::InitInstance 开始的。而且是唯一的一个入口,MFC 用它自己的 DllMain 实现对它的调用。
好了,现在让我们言归正传,讨论 .NET 和托管扩展。你的 MFC DLL 运行得很好,你甚至都不知道它还有一个 DllMain,现在你想调用框架。所以你 #include <mscorlib.dll>,用 /clr 开关编译,然后碰到高深莫测的 /NOENTRY 警告。为什么呢?
为了回答这个问题,我得解释一下另一个迷惑人的问题。DllMain 运行于 DLL 生命期一个重要的节骨眼上,正好是在它的加载过程当中。你无法实施在 DllMain 中想做的任何事情。尤其是调用其它 DLLs,因为它们都还没有被加载。调用其它 Dlls 需要首先加载它们,而这种加载要通过整个 DLL 加载循环链实现,你的 DLL 此时正在加载过程中。你知道“死循环,堆栈溢出吗?”它甚至限制应用像 user32,shell32 这样的系统 DLLs 和 COM 对象。许多程序员沮丧地发现他们的 DLL 从 DllMain中调用 MessageBox 时崩溃,希望在调试期间显示一些信息。唯一个可以保证加载并从 DllMain 中安全调用的DLL是 kernel32.dll。(有关在 DllMain 中能做什么和不能做什么的更多信息参见 DllMain)。
根据以上的解释,你可能会猜测托管 DLL 哪里不对劲。只要你使用 /clr 开关,你的 DLL 就成了托管的 DLL。初始化一个托管 DLL 需要在 DllMain 期间运行不安全代码。编译器现在产生的是微软中间语言(MSIL),不是本地机器指令。只有微软的人确切知道内幕以及系统在遇到第一个 MSIL 指令时要调用多少个 DLLs。不管发生什么,你都能断定系统除了调用内核外,还有更多的调用。因此默认情况下,托管 DLLs 不会与 C 运行时库 msvcrt.lib 链接。它们没有 _DllMainCRTStartup,并且不会调用 DllMain——即便它存在。换句话说,为了防止在 DLL 初始化期间调用不安全代码,微软的人直接规定托管 DLLs 将是一个 /NOENTRY DLLs。/NOENTRY DLL 即是一个没有 入口点的 DLL。如果你的 DLL 本身不需要初始化或终止例程,它便不需要 DllMain,因此你可以使用 /NOENTRY 选项。这样的 DLLs 不能有需要初始化的静态对象;只能输出函数。
更多精彩
赞助商链接