崩溃引发 APPCRASH 异常 0xc0000602,参考回
combase.dll
combase.dll
used 0xc0000602
(STATUS_FAIL_FAST_EXCEPTION
) 代码仅来自
void CrashProcessWithWERReport();
(这称为RaiseFailFastException https://msdn.microsoft.com/en-us/library/windows/desktop/dd941688(v=vs.85).aspx用这个代码)
CrashProcessWithWERReport
仅从以下位置调用DecrementMTAUsageHelper
满足 2 个条件 -CoDecrementMTAUsage https://msdn.microsoft.com/en-us/library/windows/desktop/jj151606(v=vs.85).aspx呼叫次数多于CoIncrementMTAUsage https://msdn.microsoft.com/en-us/library/windows/desktop/jj151607(v=vs.85).aspx or (我几乎可以肯定,因为这个原因) DecrementMTAUsageHelper
当调用线程持有Loader临界区时调用——因此在DLL加载或卸载过程中。来自 MSDN
进程关闭期间不要调用 CoDecrementMTAUsage或里面
DLL主程序。您可以在调用开始之前调用 CoDecrementMTAUsage
关机过程。
所以我的猜测 - 一些代码调用CoDecrementMTAUsage https://msdn.microsoft.com/en-us/library/windows/desktop/jj151606(v=vs.85).aspx在你的DLL卸载过程中(当你调用FreeLibrary
)
你的DLL不能直接调用CoIncrementMTAUsage https://msdn.microsoft.com/en-us/library/windows/desktop/jj151607(v=vs.85).aspx / CoDecrementMTAUsage https://msdn.microsoft.com/en-us/library/windows/desktop/jj151606(v=vs.85).aspx因为这个新的 API 是从 win 8 开始存在的(还要检查你在 win 8.1 上的代码 - 我认为也会崩溃),但是这个 api 可以从其他系统组件间接调用。
我可以假设你的DLL没有直接释放一些使用过的资源或者你调用FreeLibrary
当 DLL 仍然持有一些资源时(所以你调用FreeLibrary
没有从 DLL 进行适当的清理调用),因此该资源开始释放(CoDecrementMTAUsage
) 卸载过程中
尝试调试此问题的下一步是什么?
您需要使用符号文件进行调试(例如使用 winDbg)。设置断点于DecrementMTAUsageHelper
, CoDecrementMTAUsage
有可能CoIncrementMTAUsage
- 我打的电话对吗RtlIsCriticalSectionLockedByThread
return TRUE
(这个API从开始调用DecrementMTAUsageHelper
).
无论如何,将线程调用堆栈发布在DecrementMTAUsageHelper
呼叫点(就在崩溃之前)并且可能在CoIncrementMTAUsage
too
- - - - - - - - - - - 编辑 - - - - - - - - - - - - -
通过查看 DLL 调用可见的堆栈跟踪DestroyWindow
来自 DllMain。
apphelp!DWM8AND16BitHook_DestroyWindow
这是错误,只有两个原因 - 首先 - 阅读本文 https://blogs.msdn.microsoft.com/oldnewthing/20090626-00/?p=17733 -
获取DLL_PROCESS_DETACH通知的线程不是
必然是获得 DLL_PROCESS_ATTACH 通知的那个。你
无法在 DLL_PROCESS_ATTACH 中对线程关联执行任何操作,或者
DLL_PROCESS_DETACH 处理程序,因为您无法保证哪个
将调用线程来处理这些进程通知。这
这是一个典型的例子,我被告知开发者支持团队正在运行这个例子
以惊人的频率进入,是一个DLL,它在其内部创建一个窗口
DLL_PROCESS_ATTACH 处理程序并在其 DLL_PROCESS_DETACH 中销毁它
处理程序。
但是你的崩溃是由于另一个原因,没有在文章中列出 - DllMain 有很多限制 https://msdn.microsoft.com/en-us/library/windows/desktop/dn633971(v=vs.85).aspx#general_best_practices,里面有什么不能叫的。尽管DestroyWindow
此处未直接列出,但如您的情况所示 - 这是非法调用(即使我们在创建此窗口的同一个线程上调用) - 当您的窗口被销毁时imm32.CtfImmNotify(msctf!TF_Notify)
叫做
0019fa9c 74c17ff1 a6d0e607 000b0792 74ed48f0 imm32!CtfImmCoUninitialize+0x48
0019fb7c 74809ea6 00050004 000d06f6 00000000 msctf!TF_Notify+0x581
0019fb98 748080dc 00050004 000d06f6 00000000 user32!CtfHookProcWorker+0x36
0019fbe0 74807fa6 0019fc34 0019fc24 00000000 user32!CallHookWithSEH+0x5c
结果取消初始化 https://msdn.microsoft.com/en-us/library/windows/desktop/ms688715(v=vs.85).aspx is 从 DllMain 调用 !
来自 MSDN
不要从
DllMain函数。
这里里面FINAL 取消初始化 https://msdn.microsoft.com/en-us/library/windows/desktop/ms688715(v=vs.85).aspx called DecrementMTAUsage
这决定了我们通过调用来锁定加载器内部RtlIsCriticalSectionLockedByThread
and CrashProcessWithWERReport
called.
解决方案 ?
当然最好是修复 DLL,但如果这是不可能的 - 认为下一个“黑客”将会起作用
HRESULT hr = CoInitialize(0); // asume that we in STA
FreeLibrary(hDLL);
if (0 <= hr) CoUninitialize();
有了这个取消初始化 https://msdn.microsoft.com/en-us/library/windows/desktop/ms688715(v=vs.85).aspx当然无论如何都会被调用imm32!CtfImmCoUninitialize
但这将是不是最终版本取消初始化并作为结果DecrementMTAUsage
不会被调用