gpt4 book ai didi

windows - 进程外 COM 服务器卡住

转载 作者:可可西里 更新时间:2023-11-01 12:26:00 31 4
gpt4 key购买 nike

我正在使用进程外 COM 服务器(使用 DECLARE_CLASSFACTORY_SINGLETON 实现的 COM 单例“引擎”),它在 STA(CComSingleThreadModel,_ATL_APARTMENT_THREADED)中工作。

COM 服务器客户端:

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

BHO 周期性调用Engine::dispatchEvent,Engine 调用ActiveScript 的JavaScript 函数。在我同时打开两个 BHO 之前,此架构一直运行良好。

如果我打开两个 BHO,当我调用 ActiveScript 的函数(使用 IDispatch/Invoke)时会发生卡住。我不创建任何额外的线程。

一些注意事项:

  • 如果我不将从 BHO 检索到的对象传递给 ActiveScript(或用引擎中创建的相同对象替换它),一切正常。
  • 只有当 JScript 垃圾收集器试图释放从 BHO 检索到的对象(调用堆栈中的 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, 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++
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, 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);
}
}
}

最佳答案

您的 BHO(浏览器助手对象)位于单线程单元中。一个 STA 中对另一个 STA(不同线程)上的对象进行的每个 COM 调用在消息队列中的消息在方法调用中“转换”之前由消息排序。

这通常不是问题,因为大多数时候调用是由单线程的 GUI 触发的。 COM 调用与 WM_LBUTTONUP 消息等一起等待轮到。

在您的情况下发生的情况是,在为 onEvent 提供服务时,您将 BHO 对象发送到另一个线程,在另一个进程中,您的进程外 COM 对象。当您尝试从您的 MTA 公寓回调原始对象时,一条 Windows 消息将发布到托管它的 Internet Explorer 进程中的 BHO STA 线程。但消息队列仍在忙于为原始请求提供服务。

这解释了您的僵局,以及为什么传递字符串有效。

关于windows - 进程外 COM 服务器卡住,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14703533/

31 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com