Windows – Out-of-proc COM服务器卡住

前端之家收集整理的这篇文章主要介绍了Windows – Out-of-proc COM服务器卡住前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
我使用out-of-proc COM服务器(COM单例“Engine”使用DECLARE_CLASSFACTORY_SINGLETON实现),它在STA(CComSingleThreadModel,_ATL_APARTMENT_THREADED)中工作.

COM服务器客户端:

> ActiveScript(JScript),(我使用AddNamedItem传递引擎引用).
>两个独立的IE BHO.

BHO定期调用Engine :: dispatchEvent,Engine调用ActiveScript的JavaScript函数.
这个架构完美地工作,直到我同时打开两个BHO.

如果我打开两个BHO,当我调用ActiveScript的功能(使用IDispatch / Invoke)时,卡住了.
我不创建任何额外的线程.

一些注释:

>如果我没有将从BHO检索到的对象传递给ActiveScript(或将其替换为在Engine中创建的相同对象),一切都可以正常运行.
>只有当JScript垃圾收集器尝试释放从BHO检索到的对象(Callstack中的IUnknown_Release_Proxy)时,才会发生卡住.

调用堆栈:

>    ntdll.dll!_ZwWaitForMultipleObjects@20()  + 0x15 bytes    
 ntdll.dll!_ZwWaitForMultipleObjects@20()  + 0x15 bytes    
 KernelBase.dll!_WaitForMultipleObjectsEx@20()  + 0x100 bytes    
 kernel32.dll!_WaitForMultipleObjectsExImplementation@20()  + 0x8e bytes    
 user32.dll!_RealMsgWaitForMultipleObjectsEx@20()  + 0xe2 bytes    
 ole32.dll!CCliModalLoop::BlockFn(void * * ahEvent,unsigned long cEvents,unsigned long * lpdwSignaled)  Line 1222    C++
 ole32.dll!ModalLoop(CMessageCall * pcall)  Line 211    C++
 ole32.dll!ThreadSendReceive(CMessageCall * pCall)  Line 4979    C++
 ole32.dll!CRpcChannelBuffer::SwitchAptAndDispatchCall(CMessageCall * * ppCall)  Line 4454 + 0x6 bytes    C++
 ole32.dll!CRpcChannelBuffer::SendReceive2(tagRPCOLEMESSAGE * pMessage,unsigned long * pstatus)  Line 4076    C++
 ole32.dll!CCliModalLoop::SendReceive(tagRPCOLEMESSAGE * pMsg,unsigned long * pulStatus,IInternalChannelBuffer * pChnl)  Line 899 + 0x17 bytes    C++
 ole32.dll!CAptRpcChnl::SendReceive(tagRPCOLEMESSAGE * pMsg,unsigned long * pulStatus)  Line 583 + 0xd bytes    C++
 ole32.dll!CCtxComChnl::SendReceive(tagRPCOLEMESSAGE * pMessage,unsigned long * pulStatus)  Line 734 + 0xa bytes    C++
 ole32.dll!NdrExtpProxySendReceive(void * pThis,_MIDL_STUB_MESSAGE * pStubMsg)  Line 1932    C++
 rpcrt4.dll!@NdrpProxySendReceive@4()  + 0xe bytes    
 rpcrt4.dll!_NdrClientCall2()  + 0x144 bytes    
 ole32.dll!ObjectStublessClient(void * ParamAddress,long Method)  Line 474 + 0x8 bytes    C++
 ole32.dll!_ObjectStubless@0()  Line 154    Asm
 ole32.dll!RemoteReleaseRifRefHelper(IRemUnknown * pRemUnk,int fReleaseRemUnkProxy,int fProcessingPostedMessage,OXIDEntry * pOXIDEntry,unsigned short cRifRef,tagREMINTERFACEREF * pRifRef,IUnknown * pAsyncRelease)  Line 6770 + 0xc bytes    C++
 ole32.dll!RemoteReleaseRifRef(CStdMarshal * pMarshal,tagREMINTERFACEREF * pRifRef)  Line 6694    C++
 ole32.dll!CStdMarshal::DisconnectCliIPIDs()  Line 3964    C++
 ole32.dll!CStdMarshal::Disconnect(unsigned long dwType)  Line 3273    C++
 ole32.dll!CStdIdentity::~CStdIdentity()  Line 312    C++
 ole32.dll!CStdIdentity::`scalar deleting destructor'()  + 0xd bytes    C++
 ole32.dll!CStdIdentity::CInternalUnk::Release()  Line 767    C++
 ole32.dll!IUnknown_Release_Proxy(IUnknown * This)  Line 1773    C++
 oleaut32.dll!_VariantClear@4()  + 0xac9 bytes    
 jscript.dll!VAR::Clear()  + 0x50 bytes    
 jscript.dll!GcAlloc::ReclaimGarbage()  + 0xa2 bytes    
 jscript.dll!GcContext::Reclaim()  + 0x8e bytes    
 jscript.dll!GcContext::CollectCore()  - 0x72f bytes    
 jscript.dll!GcContext::Collect()  + 0x34 bytes    
 jscript.dll!CScriptRuntime::Run()  - 0x864f bytes    
 jscript.dll!ScrFncObj::CallWithFrameOnStack()  + 0xf3 bytes    
 jscript.dll!ScrFncObj::Call()  + 0x84 bytes    
 jscript.dll!NameTbl::InvokeInternal()  + 0x113 bytes    
 jscript.dll!VAR::InvokeByDispID()  + 0x73 bytes    
 jscript.dll!CScriptRuntime::Run()  + 0x1d89 bytes    
 jscript.dll!ScrFncObj::CallWithFrameOnStack()  + 0xf3 bytes    
 jscript.dll!ScrFncObj::Call()  + 0x84 bytes    
 jscript.dll!NameTbl::InvokeInternal()  + 0x113 bytes    
 jscript.dll!VAR::InvokeByDispID()  + 0x73 bytes    
 jscript.dll!CScriptRuntime::Run()  + 0x1d89 bytes    
 jscript.dll!ScrFncObj::CallWithFrameOnStack()  + 0xf3 bytes    
 jscript.dll!ScrFncObj::Call()  + 0x84 bytes    
 jscript.dll!NameTbl::InvokeInternal()  + 0x12c6 bytes    
 jscript.dll!VAR::InvokeByDispID()  + 0x73 bytes    
 jscript.dll!NameTbl::GetVal()  + 0x3b bytes

实施细节:

// Engine (out of process COM singleton)

class ATL_NO_VTABLE CEngine :
    public CComObjectRootEx<CComSingleThreadModel>,public CComCoClass<CEngine,&CLSID_Engine>,public IDispatchImpl<IEngine,&IID_IEngine,&LIBID_EngineLib,/*wMajor =*/ 1,/*wMinor =*/ 0>
{

    DECLARE_CLASSFACTORY_SINGLETON(CEngine)

    STDMETHOD(dispatchEvent)(BSTR name,IDispatch* pEvent,VARIANT_BOOL* pbSuccess)
    {
        // pEvent is CPropertyStore instance
        ActiveScriptDispatch.Invoke1(L"FuncName",pEvent,&varResult);
    }
}


// BHO

class CPropertyStore :
    public CComObjectRootEx<CComSingleThreadModel>,public CComCoClass<CPropertyStore,&CLSID_NULL>,public IDispatch
{
    BEGIN_COM_MAP(CPropertyStore)
        COM_INTERFACE_ENTRY(IUnknown)
        COM_INTERFACE_ENTRY(IDispatch)
    END_COM_MAP()

    BOOL SetProperty(CString strName,VARIANT *value)
    {
        // Store value in CAtlArray
    }

    // IDispatch impl
    STDMETHOD(GetTypeInfoCount)(UINT *pctinfo);
    STDMETHOD(GetTypeInfo)(UINT iTInfo,LCID lcid,ITypeInfo **ppTInfo);
    STDMETHOD(GetIDsOfNames)(REFIID riid,LPOLESTR *rgszNames,UINT cNames,DISPID *rgDispId);
    STDMETHOD(Invoke)(DISPID dispIdMember,REFIID riid,WORD wFlags,DISPPARAMS *pDispParams,VARIANT *pVarResult,EXCEPINFO *pExcepInfo,UINT *puArgErr);
}

class ATL_NO_VTABLE CBHO :
    public CComObjectRootEx<CComSingleThreadModel>,public CComCoClass<CBHO,&CLSID_BHO>,public IObjectWithSiteImpl<CBHO>,public IDispatchImpl<IBHO,&IID_IBHO,&LIBID_Lib,/*wMinor =*/ 0>,public IDispEventImpl<1,CBHO,&DIID_DWebBrowserEvents2,&LIBID_SHDocVw,1,0>
{
    void onEvent(...)
    {
        if(m_pEngine == NULL && SUCCEEDED(m_pEngine.CoCreateInstance(CLSID_Engine)))
        {
            CComObject<CPropertyStore> *pEvent = NULL;
            HRESULT hRes = CComObject<CPropertyStore>::CreateInstance(&pEvent);

            CComVariant varEvent(pEvent);
            CComVariant varName(L"EventName");
            CComVariant varResult;

            m_pEngine.Invoke2(L"dispatchEvent",&varName,&varEvent,&varResult);
        }
    }
}
@H_301_28@ 您的BHO(浏览器助手对象)位于单线程公寓中.在另一个STA(不同的线程)上的一个对象的STA中的每个COM调用在消息队列中被消息排序,然后在方法调用中“转换”.

这通常不是问题,因为大多数时间的呼叫是由单线程的GUI触发的. COM电话等待WM_LBUTTONUP消息等等.

在你的情况下会发生什么是在服务onEvent时,你的BHO对象发送到另一个线程,在另一个进程中,你的进程外COM对象.当您尝试从MTA appartment回调原始对象时,Windows邮件将在托管它的Internet Explorer进程中发布到您的BHO STA线程.但消息队列仍然在忙于服务原始请求.

这解释了你的僵局,以及为什么通过一个字符串的作品.

猜你在找的Windows相关文章