在C ++静态初始化之前或之后调用DllGetClassObject

问题描述 投票:1回答:2

我有一个加载到Microsoft管理控制台(MMC)的DLL。似乎它的DllGetClassObject函数正在调用已知依赖于静态初始化的第三方库的初始化函数(因此在常规C ++程序中不能在main()之前调用它)。此功能似乎失败,并且管理单元未在MMC中显示。奇怪的是,如果我从MMC中删除它并再次添加它,它会成功加载。

有关何时在DLL(回调之前和之后)中发生C ++静态初始化的信息似乎很少,并且Microsoft似乎已经删除了其“DLL最佳实践”论文,该论文在许多答案和文章中引用了这种类型的的问题。

是否有关于C ++静态初始化和DLL回调的顺序的任何地方(最好是在MSDN上)有一些权威信息?

(我已经尝试过https://docs.microsoft.com/en-us/windows/desktop/api/combaseapi/nf-combaseapi-dllgetclassobject,我希望这可以记录在案)

编辑:将有问题的函数调用从DllGetClassObject移动到DllMain似乎解决了这个问题。但仍在寻找权威文档。

编辑:从这个结果和答案得出结论,我对第三方初始化函数的问题不能由静态初始化引起,因为静态初始化应该在DllMain之前完成,因此也在DllGetClassObject之前完成。

c++ dll com
2个回答
1
投票

如果没有纵容或避免在DLL中使用C ++对象作为全局/静态,这里是您正在寻找的信息。操作顺序是:

  1. C / C ++全局/静态初始化
  2. DllMain
  3. DllGetClassObject

文档here描述了C / C ++全局/静态初始化和DllMain之间的关系。

...当链接到DLL时,VCRuntime代码提供了一个名为_DllMainCRTStartup的内部DLL入口点函数,该函数处理到DLL的Windows操作系统消息,以附加到进程或线程或从进程或线程分离。 _DllMainCRTStartup函数执行基本任务,例如堆栈缓冲区安全设置,C运行时库(CRT)初始化和终止,以及对静态和全局对象的构造函数和析构函数的调用。 _DllMainCRTStartup还为其他库(如WinRT,MFC和ATL)调用钩子函数来执行自己的初始化和终止。如果没有这个初始化,CRT和其他库以及静态变量将保持未初始化状态......

...在进程附加时,_DllMainCRTStartup函数设置缓冲区安全性检查,初始化CRT和其他库,初始化运行时类型信息,初始化和调用静态和非本地数据的构造函数,初始化线程本地存储,增加每个附加的内部静态计数器,然后调用用户或库提供的DllMain ...

您可以通过在DllMain中设置断点然后查看导致调用DllMain的堆栈帧来自己查看所有这些内容。在你的DllMain被召唤之前,你会发现很多有趣的事情已经完成。

至于DllGetClassObject:这个导出的函数不是魔法调用的。这个函数的调用者必须做3件事 - 加载你的DLL(例如,LoadLibrary),查找从DLL加载的函数的地址(例如,GetProcAddress),然后使用DllGetClassObject实现已知的签名调用该地址。您可以手动执行所有操作,但CoCreateInstance等功能会按此处所述的顺序自动执行这三项操作。调用DllMain时会自动调用LoadLibrary,并且LoadLibraryDllMain返回之后才会返回。如果DllMain返回成功代码,LoadLibrary的调用者将接收DLL的HMODULE。如果DllMain返回错误代码,调用者将永远不会有DLL的HMODULELoadLibrary将返回NULL),因此调用者甚至无法找到你的DllGetClassObject函数,更不用说它了。


0
投票

编辑:不要在DllGetClassObjectDllMain做任何“有趣”的事情。如果可以,请“按需”或稍后阶段调用初始化代码。在回调中做任何事情应该只是最后的手段(但它很可能会导致你在第一次测试时可能没有遇到的问题)。

在阅读了评论中建议的一些材料后,我得出结论

  1. 没有权威信息。就微软而言,C ++和DLL并不存在于同一个Universe中。
  2. 任何非权威信息(例如https://blogs.msdn.microsoft.com/oldnewthing/20040127-00/?p=40873/)都表明C ++和DLL的整个问题完全混乱,并且很难推荐任何一般的最佳实践。

在我的特定情况下(作为MMC管理单元加载的本机DLL),它似乎有助于简单地将“有问题”的代码移动到DllMain。但是,后来证明它在进程退出时引起了问题(死锁)。

© www.soinside.com 2019 - 2024. All rights reserved.