Windows 进程外COM服务器卡住
我使用的是out-of-proc COM服务器(使用DECLARE_CLASSFACTORY_singleton实现的COM singleton“引擎”),它可以在STA(CComSingleThreadModel,_ATL_公寓_THREADED)中工作 COM服务器客户端:Windows 进程外COM服务器卡住,windows,com,marshalling,atl,active-script,Windows,Com,Marshalling,Atl,Active Script,我使用的是out-of-proc COM服务器(使用DECLARE_CLASSFACTORY_singleton实现的COM singleton“引擎”),它可以在STA(CComSingleThreadModel,_ATL_公寓_THREADED)中工作 COM服务器客户端: ActiveScript(JScript),(我使用AddNamedItem传递引擎引用) 两个独立的IE BHO BHOs定期调用Engine::dispatchEvent,引擎调用ActiveScript的JavaS
- 如果我不将从BHO检索到的对象传递给ActiveScript(或者用引擎中创建的相同对象替换它),那么一切都正常
- 只有当JScript垃圾收集器尝试释放从BHO(调用堆栈中的IUnknown_release_代理)检索到的对象时,才会发生卡住
> 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
实施详情:
//引擎(进程外COM单例)
等级ATL\u NO\u VTABLE发动机:
公共CComObjectRootEx,
公共课程,
公共场所
{
声明类工厂单例(CEngine)
STDMETHOD(dispatchEvent)(BSTR名称、IDispatch*pEvent、变体\u BOOL*pbSuccess)
{
//pEvent是CPropertyStore实例
Invoke1(L“FuncName”、pEvent和varResult);
}
}
//BHO
类别CPropertyStore:
公共CComObjectRootEx,
公共课程,
公共卫生
{
开始COM映射(CPropertyStore)
COM_接口_条目(IUnknown)
COM_接口_条目(IDispatch)
END_COM_MAP()
BOOL SetProperty(CString strName,变量*值)
{
//在CAtlArray中存储值
}
//伊迪斯帕奇酒店
标准方法(GetTypeInfoCount)(UINT*pctinfo);
STDMETHOD(GetTypeInfo)(UINT iTInfo、LCID LCID、ITypeInfo**ppTInfo);
STDMETHOD(GetIDsOfNames)(refid-riid、LPOLESTR*rgszNames、UINT-cNames、LCID-LCID、DISPID*rgDispId);
STDMETHOD(Invoke)(DISPID DISPID成员、refid riid、LCID LCID、单词wFlags、DISPPARAMS*pDispParams、,
变型*pVarResult,EXPEPINFO*pExcepInfo,UINT*puArgErr);
}
类别ATL_NO_VTABLE CBHO:
公共CComObjectRootEx,
公共课程,
具有SiteImpl的公共对象,
公共场所,
公共IDispenTempl
{
void onEvent(…)
{
如果(m_pEngine==NULL&&成功(m_pEngine.CoCreateInstance(CLSID_引擎)))
{
CComObject*pEvent=NULL;
HRESULT hRes=ccombject::CreateInstance(&pEvent);
c变异变数事件(pEvent);
CComVariant varName(L“EventName”);
变异结果;
m_pEngine.Invoke2(L“dispatchEvent”、&varName、&varEvent、&varResult);
}
}
}
您的BHO(浏览器辅助对象)位于单线程装置中。STA中对另一个STA(不同线程)上的对象进行的每个COM调用都由消息队列中的消息排序,然后在方法调用中对其进行“转换”
这通常不是问题,因为大多数调用都是由单线程GUI触发的。COM调用会随着wmlbuttonup
消息等等待轮到它们
在您的情况下,当维护onEvent
时,您将BHO对象发送到另一个线程,在另一个进程中,您的进程外COM对象。当您尝试从MTA装置回拨原始对象时,会在承载该对象的Internet Explorer进程中将Windows消息发布到BHO STA线程。但是消息队列仍然忙于处理原始请求
这就解释了死锁,以及传递字符串的原因 是的,当Javascript试图释放对象时,由于所需的线程上下文切换而导致死锁。您需要查看最初创建对象的线程,并了解为什么它没有响应。如果它被阻止,那么您需要MsgWaitForMultipleObjectsEx来允许此封送调用完成。BHO线程没有响应,因为它正在等待dispatchEvent结果(oleaut32.dll!_IDispatch_Invoke_Proxy,user32.dll!_RealMsgWaitForMultipleObjectsEx,在callstack中)。我添加了实现细节。看起来像脚本引擎(它是垃圾收集器)正在释放属于不同单元的对象。您的引擎是STA,是在MTA中还是在另一个STA中执行脚本操作?如果是MTA,则应重新设计以在调用时不阻止STA(例如,来自工作线程的dispatchEvent,不确定在没有看到代码的情况下是否可以执行此操作).Scripting操作应在STA中,即使用CoCreateInstance(L“JScript”)在引擎中创建的ActiveScript中。这并不完全正确。只有对STA对象的跨单元调用才能通过消息队列处理启动。此外,常规STA(与带有自定义
IMessageFilter
或WInRT的ASTA的STA相比)当跨单元调用从它发出时处理消息,因此它是可重入的,不应该像那样死锁。我认为op没有提供足够的细节来解决问题,死锁在其他地方。你说得对,只有跨单元调用使用Windows消息,我会更新我的答案。但我记得“绊倒了”在这样一个死锁和Windows消息不可重入的情况下,问题就来了。我承认这是十多年前的事了。跟你说的一样,我的记忆一定在衰退。。。