Поток зависает при вызове AccessibleChildren

Время от времени мое приложение на C ++ будет обходить дерево MSAA из нескольких приложений, используя код, основанный на примере MSDN с этой страницы: https://msdn.microsoft.com/en-us/library/windows/desktop/dd317975(v=vs.85).aspx

Он работал отлично, пока несколько месяцев назад я не заметил, что иногда поток останавливается при вызове AccessibleChildren.

Вот что я знаю об этом:

  • Это происходит не слишком часто
  • Это происходит при ходьбе по деревьям разных приложений.
  • Это определенно не связано с количеством потомков текущего узла, так как я уже отлаживал мини-дампы, где нижний вызов childCount равный 1.
  • Это происходит на разных компьютерах.
  • Нить в таком положении никогда не проснется. Как только произойдет зависание, поток будет оставаться в этом состоянии до тех пор, пока приложение не будет перезапущено.
  • Иногда поток просто умирает во время таких итераций, и в таких случаях я не могу поймать его стек. Тогда остальная часть приложения продолжает работать, но дампы показывают, что данный поток больше не работает, хотя его задача — в основном бесконечный цикл со сном. Я предполагаю, что это связано с зависаниями. как-то.

У меня вопрос: может ли кто-нибудь указать причины такого замораживания и как их предотвратить? Если нет, то есть ли способ перенести рекурсию в другой поток, который можно было бы безопасно «тайм-аутить» из другого потока?

Это пример трассировки стека таких событий, где top — это наиболее вложенный вызов. Я удалил свою рекурсию отсюда, чтобы немного сократить чтение.

--> ntdll.dll!_NtWaitForMultipleObjects@20()    Unknown
ntdll.dll!_NtWaitForMultipleObjects@20()    Unknown
KERNELBASE.dll!_WaitForMultipleObjectsEx@20()   Unknown
kernel32.dll!_WaitForMultipleObjectsExImplementation@20()   Unknown
user32.dll!_RealMsgWaitForMultipleObjectsEx@20()    Unknown
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    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   C++
ole32.dll!CAptRpcChnl::SendReceive(tagRPCOLEMESSAGE * pMsg, unsigned long * pulStatus) Line 583 C++
ole32.dll!CCtxComChnl::SendReceive(tagRPCOLEMESSAGE * pMessage, unsigned long * pulStatus) Line 659 C++
ole32.dll!NdrExtpProxySendReceive(void * pThis, _MIDL_STUB_MESSAGE * pStubMsg) Line 1932    C++
rpcrt4.dll!@NdrpProxySendReceive@4()    Unknown
rpcrt4.dll!_NdrClientCall2()    Unknown
ole32.dll!ObjectStublessClient(void * ParamAddress, long Method) Line 474   C++
ole32.dll!_ObjectStubless@0() Line 154  Unknown
ole32.dll!CStdMarshal::Begin_RemQIAndUnmarshal1(unsigned short cIIDs, _GUID * pIIDs, tagQICONTEXT * pQIC) Line 4551 C++
ole32.dll!CStdMarshal::Begin_QueryRemoteInterfaces(unsigned short cIIDs, _GUID * pIIDs, tagQICONTEXT * pQIC)    C++
ole32.dll!CStdMarshal::QueryRemoteInterfaces(unsigned short cIIDs, _GUID * pIIDs, tagSQIResult * pQIRes) Line 4284  C++
ole32.dll!CStdIdentity::CInternalUnk::QueryMultipleInterfaces(unsigned long cMQIs, tagMULTI_QI * pMQIs) Line 596    C++
ole32.dll!CStdIdentity::CInternalUnk::QueryInterface(const _GUID & riid, void * * ppv) Line 352 C++
ole32.dll!IUnknown_QueryInterface_Proxy(IUnknown * This, const _GUID & riid, void * * ppv) Line 1723    C++
ole32.dll!CoUnmarshalInterface(IStream * pStm, const _GUID & riid, void * * ppv) Line 996   C++
oleacc.dll!UnmarshalInterface(unsigned char const *,unsigned long,struct _GUID const &,void * *)    Unknown
oleacc.dll!FreeUpSlot(struct OutstandingObjectEntry *)  Unknown
oleacc.dll!_ObjectFromLresult@16()  Unknown
oleacc.dll!NativeIAccessibleFromWindow(struct HWND__ *,unsigned long,struct _GUID const &,void * *) Unknown
oleacc.dll!_ORIGINAL_AccessibleObjectFromWindow@16()    Unknown
oleacc.dll!_AccessibleObjectFromWindow@16() Unknown
oleacc.dll!GetWindowObject(struct HWND__ *,struct tagVARIANT *) Unknown
oleacc.dll!CClient::Next(unsigned long,struct tagVARIANT *,unsigned long *) Unknown
oleacc.dll!AccWrap_Base::Next(unsigned long,struct tagVARIANT *,unsigned long *)    Unknown
oleacc.dll!_AccessibleChildren@20() Unknown
//my recursion ends here

0

Решение

Я до сих пор не знаю, почему все вышеперечисленное происходит и как защитить свое приложение от этого из моего кода. Единственное решение, которое я сам себе решил, — это использовать отдельный процесс и ждать его с некоторым таймаутом. Что-то вроде этот пример Microsoft, но с таймаутом, установленным на постоянное значение (например, полсекунды), а не INFINITE,

Если ожидание заканчивается из-за того, что процесс завершен, я получу его стандартный вывод (какой-то json с результатом или что-то в этом роде). Если время ожидания истекло, я просто прерву его, чтобы очистить его ресурсы.

Не идеальное решение, но оно даст мне некоторый контроль над происходящим, и я каким-то образом буду защищен от утечек памяти и т. Д.

Поскольку это только половина меры, я с радостью приму любые другие идеи для решения своих проблем.

0

Другие решения


По вопросам рекламы [email protected]