2013-02-05 64 views
15

मैं आउट-ऑफ-प्रो COM सर्वर (COM सिंगलटन "इंजन" का उपयोग कर रहा हूं DECLARE_CLASSFACTORY_SINGLETON का उपयोग करके कार्यान्वित), यह एसटीए (CComSingleThreadModel, _ATL_APARTMENT_THREADED) में काम करता है।आउट-ऑफ-प्रो COM सर्वर

COM सर्वर ग्राहकों:

  1. ActiveScript (JScript), (मैं AddNamedItem का उपयोग कर इंजन संदर्भ पारित)।
  2. दो स्वतंत्र आईई बीएचओ।

बीएचओ समय-समय पर इंजन :: dispatchEvent, इंजन को सक्रिय स्क्रिप्ट के जावास्क्रिप्ट कार्यों को कॉल करता है। यह आर्किटेक्चर पूरी तरह से काम करता है जब तक कि मैं एक साथ दो बीएचओ चालू नहीं करता।

यदि मैं दो बीएचओ चालू करता हूं, तो अटक जाता है जब मैं सक्रिय स्क्रिप्ट का कार्य करता हूं (IDISpatch/Invoke का उपयोग करके)। मैं कोई अतिरिक्त धागा नहीं बनाता हूं।

कुछ नोट:

  • मैं BHO से ActiveScript को पुनः प्राप्त वस्तु पारित नहीं करते हैं (या इंजन में बनाए गए एक ही वस्तु के साथ बदलने) सब कुछ ठीक काम करता है।
  • अटक तब होती है जब जेस्क्रिप्ट कचरा कलेक्टर बीएचओ (IUnknown_Release_Proxy में कॉलस्टैक) से पुनर्प्राप्त ऑब्जेक्ट को रिलीज़ करने का प्रयास करता है।

Callstack:

> [email protected]() + 0x15 bytes  
[email protected]() + 0x15 bytes  
[email protected]() + 0x100 bytes  
[email protected]() + 0x8e bytes  
[email protected]() + 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++ 
[email protected]@4() + 0xe bytes  
rpcrt4.dll!_NdrClientCall2() + 0x144 bytes  
ole32.dll!ObjectStublessClient(void * ParamAddress, long Method) Line 474 + 0x8 bytes C++ 
[email protected]() 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, OXIDEntry * pOXIDEntry, unsigned short cRifRef, 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++ 
[email protected]() + 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, LCID lcid, DISPID *rgDispId); 
    STDMETHOD(Invoke)(DISPID dispIdMember, REFIID riid, LCID lcid, 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, /*wMajor =*/ 1, /*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); 
     } 
    } 
} 
+1

हाँ, आवश्यक थ्रेड संदर्भ स्विच के कारण डेडलॉक जब जावास्क्रिप्ट आपकी ऑब्जेक्ट को रिलीज़ करने का प्रयास करता है। आपको उस थ्रेड को देखने की ज़रूरत है जिसने मूल रूप से ऑब्जेक्ट बनाया है और देखें कि यह उत्तरदायी क्यों नहीं है। यदि यह अवरुद्ध है तो आपको इस मार्शल कॉल को पूरा करने के लिए MsgWaitForMultipleObjectsEx की आवश्यकता है। –

+0

बीएचओ थ्रेड प्रतिक्रिया नहीं दे रहा है क्योंकि यह प्रेषण के लिए इंतजार कर रहा है परिणाम (oleaut32.dll! _IDispatch_Invoke_Proxy, user32.dll! _RealMsgWaitForMultipleObjectsEx कॉलस्टैक में)। – KAdot

+0

मैंने कार्यान्वयन विवरण जोड़ा है। – KAdot

उत्तर

0

आपका BHO (ब्राउज़र सहायक वस्तु) को एक ही धागे अपार्टमेंट में है। एक एसटीए में प्रत्येक COM कॉल जिसे किसी अन्य एसटीए (अलग थ्रेड) पर किसी ऑब्जेक्ट में बनाया जाता है, उसे एक संदेश कतार में एक संदेश द्वारा आदेश दिया जाता है, इससे पहले कि यह एक विधि कॉल में "रूपांतरित" हो।

यह आमतौर पर एक समस्या नहीं है, क्योंकि ज्यादातर समय कॉल जीयूआई द्वारा ट्रिगर किया जाता है जो सिंगल थ्रेडेड होता है। COM कॉल WM_LBUTTONUP संदेशों और इस तरह के साथ अपनी बारी का इंतजार करते हैं।

आपके मामले में क्या होता है कि onEvent सर्विस करते समय, आप अपनी बीएचओ ऑब्जेक्ट को किसी अन्य प्रक्रिया में भेजते हैं, एक अन्य प्रक्रिया में, आपकी आउट ऑफ़ प्रोसेस ऑब्जेक्ट। जब आप अपने एमटीए एपमेंट से मूल ऑब्जेक्ट पर वापस कॉल करने का प्रयास करते हैं, तो एक इंटरनेट संदेश आपके बीएचओ एसटीए थ्रेड पर इंटरनेट एक्सप्लोरर प्रक्रिया में पोस्ट किया जाता है जो इसे होस्ट करता है। लेकिन संदेश कतार अभी भी मूल अनुरोध की सेवा में व्यस्त है।

यह आपके डेडलॉक को बताता है, और एक स्ट्रिंग काम क्यों गुजरता है।

+0

यह पूरी तरह से सही नहीं है। संदेश कतार प्रसंस्करण द्वारा शुरू की गई एसटीए ऑब्जेक्ट पर केवल क्रॉस-अपार्टमेंट कॉल। इसके अलावा, नियमित एसटीए (एक कस्टम 'IMessageFilter' या WINRT के एएसटीए के साथ एक एसटीए बनाम) संदेश को संसाधित करता है जब क्रॉस-अपार्टमेंट कॉल से बने होते हैं, इसलिए यह पुनर्विक्रेता है और इसे इस तरह से डेडलॉक नहीं करना चाहिए। मुझे लगता है कि ओप ने समस्या को हल करने के लिए पर्याप्त विवरण नहीं दिए थे, डेडलॉक कहीं और है। – acelent

+0

आप सही कह रहे हैं कि केवल क्रॉस अपार्टमेंट कॉल विंडोज संदेशों का उपयोग करते हैं, मैं अपना जवाब अपडेट करूंगा। लेकिन मुझे याद है कि ऐसे मृत लॉक पर "ठोकरें" और विंडोज संदेशों की गैर-पुनर्वितरण समस्या थी। मैं मानता हूं कि यह 10 साल पहले था। [यह पोस्ट] (http://blogs.msdn.com/b/timng/archive/2006/09/06/743795.aspx) आपके जैसा ही कहता है, मेरी याददाश्त मुझे विफल करनी चाहिए ... – ixe013