在基于.NET的COM对象的CoCreateInstance期间挂起的应用程序 [英] Application hanging during CoCreateInstance of .NET-based COM object

查看:726
本文介绍了在基于.NET的COM对象的CoCreateInstance期间挂起的应用程序的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个C ++ DLL,它正在创建一个在.NET中实现的COM对象的实例。在许多情况下,这工作正常,但在某些情况下,它挂起的应用程序,我看到它与下面的调用堆栈(这只是我的DLL的代码的水平下面的部分):

  ntdll.dll!_NtAlpcSendWaitReceivePort@32()
rpcrt4.dll!LRPC_CASSOCIATION :: AlpcSendWaitReceivePort(unsigned long,struct _PORT_MESSAGE *,struct _ALPC_MESSAGE_ATTRIBUTES *,struct _PORT_MESSAGE *,unsigned long *,struct _ALPC_MESSAGE_ATTRIBUTES *,union _LARGE_INTEGER *)
rpcrt4.dll!LRPC_BASE_CCALL :: DoSendReceive(void)
rpcrt4.dll!LRPC_BASE_CCALL :: SendReceive(struct _RPC_MESSAGE *)
rpcrt4.dll!_I_RpcSendReceive@4()
rpcrt4.dll!_NdrSendReceive@8()
rpcrt4.dll!@ NdrpSendReceive @ 4()
rpcrt4.dll!_NdrClientCall2()
combase.dll!ServerAllocateOXIDAndOIDs(无效* hServer,无效* phProcess,无符号__int64 * poxidServer,无符号长皮质激素,无符号__int64 * aOid,无符号长* pcOidsAllocated,常量tagOXID_INFO * poxidInfo,tagDUALSTRINGARRAY * pdsaStringBindings,tagDUALSTRINGARRAY * pdsaSecurityBindings,无符号__int64 * pdwOrBindingsID,tagDUALSTRINGARRAY * * ppdsaOrBindings)行246
combase.dll!CRpcResolver :: ServerRegisterOXID(const tagOXID_INFO& oxidInfo,无符号__int64 * poxid,无符号长* pcOidsToAllocate,无符号__int64 * arNewOidList)线1020
combase.dll!OXIDEntry :: RegisterOXIDAndOIDs(无符号长* pcOids,无符号__int64 * POIDS)线1631
combase。 dll!OXIDEntry :: AllocOIDs(unsigned long * pcOidsAlloc,unsigned __int64 * pOidsAlloc,unsigned long cOidsReturn,unsigned __int64 * pOidsReturn)
combase.dll!CComApartment :: CallTheResolver()Line 856
combase.dll! CComApartment :: InitRemoting()Line 1166
combase.dll!CComApartment :: StartServer()Line 1386
combase.dll!InitChannelIfNecessary()Line 1393
combase.dll!ClassicSTAThreadWaitForHandles(unsigned long dwFlags ,无符号长dwTimeout,无符号长cHandles,无效* pHandles,无符号长* pdwIndex)线路34
combase.dll!CoWaitForMultipleHandles(无符号长dwFlags中,无符号长dwTimeout,无符号长cHandles,无效* pHandles,无符号长* lpdwindex)
mscorwks.dll!NT5WaitRoutine(int,unsigned long,int,void * *,int)
mscorwks.dll!MsgWaitHelper(int,void * *,int,unsigned long,int)
mscorwks.dll Thread :: DoAppropriateAptStateWait(int,void * *,int,unsigned long,enum WaitMode)
mscorwks.dll Thread :: DoAppropriateWaitWorker(int,void *枚举WaitMode)
mscorwks.dll!Thread :: DoAppropriateWait(int,void * *,int,unsigned long,enum WaitMode,struct PendingSync *)
mscorwks.dll CLREvent :: WaitEx枚举WaitMode,struct PendingSync *)
mscorwks.dll CLREvent :: Wait(unsigned long,int,struct PendingSync *)
mscorwks.dll CExecutionEngine :: WaitForEvent(void *,unsigned long,int)
mscorwks.dll!ClrWaitEvent(void *,unsigned long,int)
mscorwks.dll!FusionSink :: Wait(void)
mscorwks.dll!AssemblySink :: Wait(void)
的Mscorwks.dll!FusionBind :: RemoteLoad(结构IApplicationContext接口*,类FusionSink *,结构* IAssemblyName,结构IAssembly *,无符号短常量*,结构IAssembly *,结构IHostAssembly *,结构IAssembly *,INT)
mscorwks.dll!FusionBind :: LoadAssembly(struct IApplicationContext *,class FusionSink *,struct IAssembly * *,struct IHostAssembly * *,struct IAssembly * *,int)
mscorwks.dll!AssemblySpec :: FindAssemblyFile类AppDomain *,int,struct IAssembly * *,struct IHostAssembly * *,struct IAssembly * *,struct IFusionBindLog * *,enum StackCrawlMark *)
mscorwks.dll!AppDomain :: BindAssemblySpec(AssemblySpec *,int,int ,枚举StackCrawlMark *)
mscorwks.dll!AssemblySpec :: LoadDomainAssembly(枚举FileLoadLevel,类Object * *,类Object * *,int,int,int,枚举StackCrawlMark *)
mscorwks.dll!AssemblySpec :: LoadAssembly(enum FileLoadLevel,class Object * *,class Object * *,int,int,int,enum StackCrawlMark *)
mscorwks.dll!AppDomain :: LoadAssemblyHelper(unsigned short const *
mscorwks.dll!AppDomain :: LoadCOMClass(s​​truct _GUID,int,int *)
mscorwks.dll!GetTypeForCLSID(struct _GUID const&,int *)
mscorwks.dll!EEDllGetClassObject struct _GUID const&,struct _GUID const&,void * *)
mscorwks.dll!_InternalDllGetClassObject@12()
mscorwks.dll!_DllGetClassObjectInternal@12()
mscoreei.dll! _DllGetClassObject @ 12()
combase.dll!CClassCache :: CDllPathEntry :: GetClassObject(const _GUID& pClsid,const _GUID& pIid,void * * ppv)2691
combase.dll!CClassCache :: CDllPathEntry :: DllGetClassObject(const _GUID& rclsid,const _GUID& riid,IUnknown * * ppUnk,int fMakeValid)Line 3892
combase.dll!CClassCache :: CDllFnPtrMoniker :: BindToObjectNoSwitch(const _GUID& riid,void * * ppvResult)行4406
combase.dll!CClassCache :: GetClassObject(const ACTIVATION_PROPERTIES& ap)Line 5816
combase.dll!CServerContextActivator ::的CreateInstance(的IUnknown * pUnkOuter,IActivationPropertiesIn * pInActProperties,IActivationPropertiesOut * ppOutActProperties)线999
combase.dll!ActivationPropertiesIn :: DelegateCreateInstance(的IUnknown * pUnkOuter,IActivationPropertiesOut * ppActPropsOut)线路1854年
combase.dll!CApartmentActivator ::的CreateInstance(的IUnknown * pUnkOuter,IActivationPropertiesIn * pInActProperties,IActivationPropertiesOut * ppOutActProperties)线2323
combase.dll!CProcessActivator :: CCICallback(无符号长dwContext,*的IUnknown pUnkOuter,ActivationPropertiesIn * pActIn,IActivationPropertiesIn * pInActProperties,IActivationPropertiesOut * ppOutActProperties)
combase.dll!CProcessActivator :: AttemptActivation(ActivationPropertiesIn * pActIn,*的IUnknown pUnkOuter,IActivationPropertiesIn * pInActProperties,IActivationPropertiesOut * ppOutActProperties,HRESULT(unsigned long类型,的IUnknown *,ActivationPropertiesIn *,* IActivationPropertiesIn,IActivationPropertiesOut *。*)* pfnCtxActCallback,无符号长dwContext)线1673
combase.dll!CProcessActivator :: ActivateByContext(ActivationPropertiesIn * pActIn,*的IUnknown pUnkOuter,IActivationPropertiesIn * pInActProperties,IActivationPropertiesOut * ppOutActProperties,HRESULT(无符号长,的IUnknown *,* ActivationPropertiesIn,IActivationPropertiesIn *,IActivationPropertiesOut *。*)* pfnCtxActCallback)线1539
combase.dll!CProcessActivator ::的CreateInstance(的IUnknown * pUnkOuter,IActivationPropertiesIn * pInActProperties,IActivationPropertiesOut * ppOutActProperties)线1417
combase.dll!ActivationPropertiesIn :: DelegateCreateInstance(的IUnknown * pUnkOuter,IActivationPropertiesOut * ppActPropsOut)线路1854年
combase.dll!CClientContextActivator ::的CreateInstance(的IUnknown * pUnkOuter,IActivationPropertiesIn * pInActProperties,IActivationPropertiesOut * ppOutActProperties)线713
combase.dll!ActivationPropertiesIn :: DelegateCreateInstance(IUnknown * pUnkOuter,IActivationPropertiesOut * * ppActPropsOut)
combase.dll!ICoCreateInstanceEx(const _GUID& OriginalClsid,*的IUnknown punkOuter,无符号长dwClsCtx,_COSERVERINFO * pServerInfo,无符号长dwCount,无符号长dwActvFlags,tagMULTI_QI * pResults,ActivationPropertiesIn * pActIn)线1645
combase.dll CComActivator :: DoCreateInstance(常量_GUID&安培;!Clsid是,*的IUnknown punkOuter,无符号长dwClsCtx,_COSERVERINFO * pServerInfo,无符号长dwCount,tagMULTI_QI * pResults,ActivationPropertiesIn * pActIn)线376
combase.dll CoCreateInstance的(常量_GUID&安培;!rclsid,*的IUnknown pUnkOuter,无符号长dwContext ,const _GUID& riid,void * * ppv)行120

是满足以下所有条件时:


  1. 应用程序正在一个干净的Windows 2012 R2系统上运行,

  2. 应用程序未创建并初始化 Microsoft_InteropFormTools.InteropToolbox
  3. 应用程序以无注册的方式安装,而不是使用具有更多开销的旧安装程序,并在注册表和.NET中注册COM DLL。


  4. 如果我更改第一个条件并在我的本地Windows上运行, 7开发机代替干净的Windows 2012服务器,那么问题不会发生。如果我改变第二个条件,所以代码在创建COM对象之前初始化InteropformTools,那么也不会发生问题。如果我更改第三个条件,以便使用旧的全面安装程序安装产品,则不会发生此问题。



    如何跟踪此问题的来源, /或修复它?

    解决方案

    在Microsoft支持和DebugDiag的帮助下,我们确定问题的原因似乎是与装载机锁相关。 Loader Lock详细记录在 https:// msdn .microsoft.com / en-us / library / ms173266(v = vs.120).aspx 但基本上,有一些限制适用于在DllMain范围内运行的代码或动态初始化静态un-托管代码对象,其实例在加载DLL时需要动态初始化(因为它们在全局范围内)。解决此问题的方法是告诉C ++编译器,代码应与CLR支持,所以它不处理在DllMain中初始化被编译,而是另外一个功能是不会保留加载程序锁。



    在我们的代码中,我们有一个全局声明:

      CFSCoCultureWrapper cultureWrapper; 

    其中有一个构造函数调用 CoCreateInstance 一个托管COM对象,它又具有对Microsoft.InteropToolbox的引用。应用 / clr 切换到该源文件允许加载DLL而不挂起。



    为什么行为在不同的部署中改变,但是,作为文章链接状态,挂起不一定总是发生,因此这些可能是难以调试的问题。为了说明,即使我们的简单测试用例是我们遇到问题之前的4级深度加载DLL - EXE加载(LoadLibrary)非托管DLL加载(CoCreateInstance)托管DLL加载Microsoft DLL。我们决定参与这些各种各样的问题的复杂程度是不够好理解,并没有进一步追究理解为什么问题只发生在某些特定的部署。



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


    I have a C++ DLL that is creating an instance of a COM object that's implemented in .NET. Under many circumstances this works fine, but under certain circumstances, it hangs the application, and I see it stuck with the following call stack (this is just the part underneath the level of my DLL's code):

    ntdll.dll!_NtAlpcSendWaitReceivePort@32()
    rpcrt4.dll!LRPC_CASSOCIATION::AlpcSendWaitReceivePort(unsigned long,struct _PORT_MESSAGE *,struct _ALPC_MESSAGE_ATTRIBUTES *,struct _PORT_MESSAGE *,unsigned long *,struct _ALPC_MESSAGE_ATTRIBUTES *,union _LARGE_INTEGER *)
    rpcrt4.dll!LRPC_BASE_CCALL::DoSendReceive(void)
    rpcrt4.dll!LRPC_BASE_CCALL::SendReceive(struct _RPC_MESSAGE *)
    rpcrt4.dll!_I_RpcSendReceive@4()
    rpcrt4.dll!_NdrSendReceive@8()
    rpcrt4.dll!@NdrpSendReceive@4()
    rpcrt4.dll!_NdrClientCall2()
    combase.dll!ServerAllocateOXIDAndOIDs(void * hServer, void * phProcess, unsigned __int64 * poxidServer, unsigned long cOids, unsigned __int64 * aOid, unsigned long * pcOidsAllocated, const tagOXID_INFO * poxidInfo, tagDUALSTRINGARRAY * pdsaStringBindings, tagDUALSTRINGARRAY * pdsaSecurityBindings, unsigned __int64 * pdwOrBindingsID, tagDUALSTRINGARRAY * * ppdsaOrBindings) Line 246
    combase.dll!CRpcResolver::ServerRegisterOXID(const tagOXID_INFO & oxidInfo, unsigned __int64 * poxid, unsigned long * pcOidsToAllocate, unsigned __int64 * arNewOidList) Line 1020
    combase.dll!OXIDEntry::RegisterOXIDAndOIDs(unsigned long * pcOids, unsigned __int64 * pOids) Line 1631
    combase.dll!OXIDEntry::AllocOIDs(unsigned long * pcOidsAlloc, unsigned __int64 * pOidsAlloc, unsigned long cOidsReturn, unsigned __int64 * pOidsReturn)
    combase.dll!CComApartment::CallTheResolver() Line 856
    combase.dll!CComApartment::InitRemoting() Line 1166
    combase.dll!CComApartment::StartServer() Line 1386
    combase.dll!InitChannelIfNecessary() Line 1393
    combase.dll!ClassicSTAThreadWaitForHandles(unsigned long dwFlags, unsigned long dwTimeout, unsigned long cHandles, void * * pHandles, unsigned long * pdwIndex) Line 34
    combase.dll!CoWaitForMultipleHandles(unsigned long dwFlags, unsigned long dwTimeout, unsigned long cHandles, void * * pHandles, unsigned long * lpdwindex)
    mscorwks.dll!NT5WaitRoutine(int,unsigned long,int,void * *,int)
    mscorwks.dll!MsgWaitHelper(int,void * *,int,unsigned long,int)
    mscorwks.dll!Thread::DoAppropriateAptStateWait(int,void * *,int,unsigned long,enum WaitMode)
    mscorwks.dll!Thread::DoAppropriateWaitWorker(int,void * *,int,unsigned long,enum WaitMode)
    mscorwks.dll!Thread::DoAppropriateWait(int,void * *,int,unsigned long,enum WaitMode,struct PendingSync *)
    mscorwks.dll!CLREvent::WaitEx(unsigned long,enum WaitMode,struct PendingSync *)
    mscorwks.dll!CLREvent::Wait(unsigned long,int,struct PendingSync *)
    mscorwks.dll!CExecutionEngine::WaitForEvent(void *,unsigned long,int)
    mscorwks.dll!ClrWaitEvent(void *,unsigned long,int)
    mscorwks.dll!FusionSink::Wait(void)
    mscorwks.dll!AssemblySink::Wait(void)
    mscorwks.dll!FusionBind::RemoteLoad(struct IApplicationContext *,class FusionSink *,struct IAssemblyName *,struct IAssembly *,unsigned short const *,struct IAssembly * *,struct IHostAssembly * *,struct IAssembly * *,int)
    mscorwks.dll!FusionBind::LoadAssembly(struct IApplicationContext *,class FusionSink *,struct IAssembly * *,struct IHostAssembly * *,struct IAssembly * *,int)
    mscorwks.dll!AssemblySpec::FindAssemblyFile(class AppDomain *,int,struct IAssembly * *,struct IHostAssembly * *,struct IAssembly * *,struct IFusionBindLog * *,enum StackCrawlMark *)
    mscorwks.dll!AppDomain::BindAssemblySpec(class AssemblySpec *,int,int,enum StackCrawlMark *)
    mscorwks.dll!AssemblySpec::LoadDomainAssembly(enum FileLoadLevel,class Object * *,class Object * *,int,int,int,enum StackCrawlMark *)
    mscorwks.dll!AssemblySpec::LoadAssembly(enum FileLoadLevel,class Object * *,class Object * *,int,int,int,enum StackCrawlMark *)
    mscorwks.dll!AppDomain::LoadAssemblyHelper(unsigned short const *,unsigned short const *)
    mscorwks.dll!AppDomain::LoadCOMClass(struct _GUID,int,int *)
    mscorwks.dll!GetTypeForCLSID(struct _GUID const &,int *)
    mscorwks.dll!EEDllGetClassObject(struct _GUID const &,struct _GUID const &,void * *)
    mscorwks.dll!_InternalDllGetClassObject@12()
    mscorwks.dll!_DllGetClassObjectInternal@12()
    mscoreei.dll!_DllGetClassObject@12()
    combase.dll!CClassCache::CDllPathEntry::GetClassObject(const _GUID & pClsid, const _GUID & pIid, void * * ppv) Line 2691
    combase.dll!CClassCache::CDllPathEntry::DllGetClassObject(const _GUID & rclsid, const _GUID & riid, IUnknown * * ppUnk, int fMakeValid) Line 3892
    combase.dll!CClassCache::CDllFnPtrMoniker::BindToObjectNoSwitch(const _GUID & riid, void * * ppvResult) Line 4406
    combase.dll!CClassCache::GetClassObject(const ACTIVATION_PROPERTIES & ap) Line 5816
    combase.dll!CServerContextActivator::CreateInstance(IUnknown * pUnkOuter, IActivationPropertiesIn * pInActProperties, IActivationPropertiesOut * * ppOutActProperties) Line 999
    combase.dll!ActivationPropertiesIn::DelegateCreateInstance(IUnknown * pUnkOuter, IActivationPropertiesOut * * ppActPropsOut) Line 1854
    combase.dll!CApartmentActivator::CreateInstance(IUnknown * pUnkOuter, IActivationPropertiesIn * pInActProperties, IActivationPropertiesOut * * ppOutActProperties) Line 2323
    combase.dll!CProcessActivator::CCICallback(unsigned long dwContext, IUnknown * pUnkOuter, ActivationPropertiesIn * pActIn, IActivationPropertiesIn * pInActProperties, IActivationPropertiesOut * * ppOutActProperties)
    combase.dll!CProcessActivator::AttemptActivation(ActivationPropertiesIn * pActIn, IUnknown * pUnkOuter, IActivationPropertiesIn * pInActProperties, IActivationPropertiesOut * * ppOutActProperties, HRESULT (unsigned long, IUnknown *, ActivationPropertiesIn *, IActivationPropertiesIn *, IActivationPropertiesOut * *) * pfnCtxActCallback, unsigned long dwContext) Line 1673
    combase.dll!CProcessActivator::ActivateByContext(ActivationPropertiesIn * pActIn, IUnknown * pUnkOuter, IActivationPropertiesIn * pInActProperties, IActivationPropertiesOut * * ppOutActProperties, HRESULT (unsigned long, IUnknown *, ActivationPropertiesIn *, IActivationPropertiesIn *, IActivationPropertiesOut * *) * pfnCtxActCallback) Line 1539
    combase.dll!CProcessActivator::CreateInstance(IUnknown * pUnkOuter, IActivationPropertiesIn * pInActProperties, IActivationPropertiesOut * * ppOutActProperties) Line 1417
    combase.dll!ActivationPropertiesIn::DelegateCreateInstance(IUnknown * pUnkOuter, IActivationPropertiesOut * * ppActPropsOut) Line 1854
    combase.dll!CClientContextActivator::CreateInstance(IUnknown * pUnkOuter, IActivationPropertiesIn * pInActProperties, IActivationPropertiesOut * * ppOutActProperties) Line 713
    combase.dll!ActivationPropertiesIn::DelegateCreateInstance(IUnknown * pUnkOuter, IActivationPropertiesOut * * ppActPropsOut)
    combase.dll!ICoCreateInstanceEx(const _GUID & OriginalClsid, IUnknown * punkOuter, unsigned long dwClsCtx, _COSERVERINFO * pServerInfo, unsigned long dwCount, unsigned long dwActvFlags, tagMULTI_QI * pResults, ActivationPropertiesIn * pActIn) Line 1645
    combase.dll!CComActivator::DoCreateInstance(const _GUID & Clsid, IUnknown * punkOuter, unsigned long dwClsCtx, _COSERVERINFO * pServerInfo, unsigned long dwCount, tagMULTI_QI * pResults, ActivationPropertiesIn * pActIn) Line 376
    combase.dll!CoCreateInstance(const _GUID & rclsid, IUnknown * pUnkOuter, unsigned long dwContext, const _GUID & riid, void * * ppv) Line 120
    

    The circumstances under which the hanging occurs are when all the following conditions are met:

    1. The application is running on a clean Windows 2012 R2 system where I have just run an install that tries to install the minimal set of components for the application to run.
    2. The application is not creating and initializing an instance of Microsoft_InteropFormTools.InteropToolbox before creating the unrelated COM object.
    3. The application is installed in a reg-free manner rather than using the old installer that has much more overhead and registers COM DLLs in the registry and .NET DLLs in the GAC, and possibly includes files that the minimal installer neglected.

    If I change the first condition and run on my local Windows 7 development machine instead of the clean Windows 2012 server, then the problem doesn't occur. If I change the second condition so the code is initializing InteropformTools before creating the COM object, then also the problem doesn't occur. If I change the third condition so the product is installed using the old comprehensive installer, the problem doesn't occur.

    How do I track down the source of this problem and/or fix it?

    解决方案

    With the assistance of Microsoft support and DebugDiag we have determined that the cause of the problem seems to be related to a Loader Lock. Loader Lock is documented in detail at https://msdn.microsoft.com/en-us/library/ms173266(v=vs.120).aspx but basically, there are certain restrictions that apply to code that runs within the scope of DllMain or dynamic initialization of static un-managed code objects whose instances require dynamic initialization on loading the DLL (because they're in global scope). One way around this is to tell the C++ compiler that the code should be compiled with CLR support so it's not handling the initialization in DllMain, but rather another function that doesn't retain the loader lock.

    In our code we had a global declaration:

    CFSCoCultureWrapper cultureWrapper;
    

    Which had a constructor that called CoCreateInstance on a managed COM object, which in turn had a reference to Microsoft.InteropToolbox. Applying the /clr switch to that one source file allowed the DLL to be loaded without hanging.

    It's not clear why the behavior changed in different deployments, but, as the article linked states, the hang does not necessarily always occur, so these can be difficult problems to debug. To illustrate, even our simple test case was 4 levels deep loading DLLs before we encountered the problem - EXE loads (LoadLibrary) unmanaged DLL loads (CoCreateInstance) managed DLL loads Microsoft DLL. We decided with the level of complexity involved in these sorts of problems it was well enough understood and did not pursue further understanding why the problem only occurred in certain deployments.

    Simple answer, don't create global instances of objects that load managed code during the constructor from unmanaged code. Use lazy initialization or switch the code file to use the /clr switch or use some means of preventing the execution of managed code during DllMain-time initialization. Another work-around we discovered was switching the managed code to use .NET 4.5 instead of 2.0.

    这篇关于在基于.NET的COM对象的CoCreateInstance期间挂起的应用程序的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆