C# 基于.NET的COM对象的CoCreateInstance期间应用程序挂起 我有一个C++ DLL,它创建了一个COM对象的实例,该对象是在.NET中实现的。在许多情况下,这可以正常工作,但在某些情况下,它会挂起应用程序,我看到它被以下调用堆栈卡住(这只是我的DLL代码级别下面的部分):

C# 基于.NET的COM对象的CoCreateInstance期间应用程序挂起 我有一个C++ DLL,它创建了一个COM对象的实例,该对象是在.NET中实现的。在许多情况下,这可以正常工作,但在某些情况下,它会挂起应用程序,我看到它被以下调用堆栈卡住(这只是我的DLL代码级别下面的部分):,c#,c++,.net,com-interop,winforms-interop,C#,C++,.net,Com Interop,Winforms Interop,当满足以下所有条件时,发生悬挂的情况: 该应用程序正在干净的Windows 2012 R2系统上运行,我刚刚运行了一个安装程序,尝试安装应用程序要运行的最小组件集 在创建不相关的COM对象之前,应用程序未创建和初始化Microsoft_InteropFormTools.InteroptolBox的实例 该应用程序是以无需注册的方式安装的,而不是使用开销大得多的旧安装程序,在注册表中注册COM DLL,在GAC中注册.NET DLL,并且可能包含最小安装程序忽略的文件 如果我更改第一个条件并在本地

当满足以下所有条件时,发生悬挂的情况:

  • 该应用程序正在干净的Windows 2012 R2系统上运行,我刚刚运行了一个安装程序,尝试安装应用程序要运行的最小组件集
  • 在创建不相关的COM对象之前,应用程序未创建和初始化Microsoft_InteropFormTools.InteroptolBox的实例
  • 该应用程序是以无需注册的方式安装的,而不是使用开销大得多的旧安装程序,在注册表中注册COM DLL,在GAC中注册.NET DLL,并且可能包含最小安装程序忽略的文件
  • 如果我更改第一个条件并在本地Windows 7开发计算机上运行,而不是在干净的Windows 2012服务器上运行,那么问题就不会发生。如果我更改第二个条件,使代码在创建COM对象之前初始化InteropformTools,那么问题也不会发生。如果我更改第三个条件,以便使用旧的综合安装程序安装产品,则不会出现问题


    如何查找此问题的根源和/或修复它?

    在Microsoft支持和DebugDiag的帮助下,我们已确定问题的原因似乎与加载程序锁定有关。加载程序锁在中有详细说明,但基本上,对于在DllMain范围内运行的代码或静态非托管代码对象的动态初始化(其实例在加载DLL时需要动态初始化)(因为它们在全局范围内)存在某些限制。一种方法是告诉C++编译器,代码应该用CLR支持编译,这样它就不会处理DllMain中的初始化,而是另一个不保存加载器锁的函数。 在我们的代码中,我们有一个全球宣言:

    CFSCoCultureWrapper cultureWrapper;
    
    它有一个在托管COM对象上调用
    CoCreateInstance
    的构造函数,而托管COM对象又引用了Microsoft.InteropToolbox。将
    /clr
    开关应用于该源文件,可以在不挂起的情况下加载DLL

    不清楚为什么在不同的部署中行为会发生变化,但是,正如本文所述,挂起不一定总是发生,因此这些问题可能很难调试。举例来说,在我们遇到问题之前,即使是我们的简单测试用例也是4级深度加载DLL—EXE加载(LoadLibrary)非托管DLL加载(CoCreateInstance)托管DLL加载Microsoft DLL。我们决定,考虑到这类问题所涉及的复杂性,我们已经充分理解了这一点,并且没有进一步理解为什么问题只发生在某些部署中

    答案很简单,不要创建在构造函数期间从非托管代码加载托管代码的对象的全局实例。使用延迟初始化或切换代码文件以使用
    /clr
    开关,或使用某种方法防止在DllMain time初始化期间执行托管代码。我们发现的另一个解决方法是将托管代码改为使用.NET4.5而不是2.0

    CFSCoCultureWrapper cultureWrapper;