【发布时间】:2015-09-03 03:17:47
【问题描述】:
当我的应用程序终止时,如何使用终止前的回调来处理情况?
.NET 处理程序在以下情况下不起作用,SetUnhandledExceptionHandler 是正确的选择吗?它似乎有下面讨论的缺点。
场景
我想通过 .net 应用中的服务向我们的服务发送消息和错误报告来响应所有应用终止情况。
但是,我有一个 WPF 应用程序,其中我们的两个测试人员得到绕过的未处理异常:
- AppDomain.UnhandledException(最重要的)
- Application.ThreadException
- Dispatcher.UnhandledException
它们被标记为 SecuirtyCritical 和 HandleProcessCorruptedStateExceptions。 legacyCorruptedStateExceptionsPolicy 在 app.config 中设置为 true
我在野外的两个例子
- 在某处初始化 WPF 时,运行 widows10 的 VirtualBox 会抛出一些 vboxd3d.dll(关闭 vbox 3d 加速“修复它”)
- Win8 机器在系统上下文菜单中带有可疑选项“在显卡 A/B 上运行”,在 WPF 启动期间在某处 (:/) 崩溃,但仅在应用反破解工具时才会崩溃。
无论哪种方式,当应用上线时,应用必须在终止之前响应这些类型的故障。
我可以使用非托管异常重现此情况,该异常发生在 .net 中 PInvoked 方法的非托管线程中:
test.dll
BOOL APIENTRY DllMain( HMODULE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}
DWORD WINAPI myThread(LPVOID lpParameter)
{
long testfail = *(long*)(-9022);
return 1;
}
extern "C" __declspec(dllexport) void test()
{
DWORD tid;
HANDLE myHandle = CreateThread(0, 0, myThread, NULL, 0, &tid);
WaitForSingleObject(myHandle, INFINITE);
}
app.exe
class TestApp
{
[DllImport("kernel32.dll")]
static extern FilterDelegate SetUnhandledExceptionFilter(FilterDelegate lpTopLevelExceptionFilter);
[UnmanagedFunctionPointer(CallingConvention.StdCall)]
delegate int FilterDelegate(IntPtr exception_pointers);
static int Win32Handler(IntPtr nope)
{
MessageBox.Show("Native uncaught SEH exception"); // show + report or whatever
Environment.Exit(-1); // exit and avoid WER etc
return 1; // thats EXCEPTION_EXECUTE_HANDLER, although this wont be called due to the previous line
}
[DllImport("test.dll")]
static extern void test();
[STAThread]
public static void Main(string[] args)
{
AppDomain.CurrentDomain.UnhandledException += new UnhandledExceptionEventHandler(CurrentDomain_UnhandledException);
SetUnhandledExceptionFilter(Win32Handler);
test(); // This is caught by Win32Handler, not CurrentDomain_UnhandledException
}
[SecurityCritical, HandleProcessCorruptedStateExceptions ]
static void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
{
Exception ex = e.ExceptionObject as Exception;
MessageBox.Show(ex.ToString()); // show + report or whatever
Environment.Exit(-1); // exit and avoid WER etc
}
}
这会处理裸 WPF 测试应用程序中 vboxd3d.dll 中的故障,该应用程序当然也注册了 WCF 调度程序和 WinForms 应用程序(为什么不)异常处理程序。
更新
- 在我尝试使用它的生产代码中,处理程序似乎被其他调用者覆盖,我可以通过每 100 毫秒调用一次方法来解决这个问题,这当然是愚蠢的。
- 在存在 vbox3d.dll 问题的机器上,执行上述操作会将异常替换为 clr.dll 中的异常。
- 出现崩溃时,传递给kernel32的托管函数指针不再有效。使用本机帮助程序 dll 设置处理程序,该程序调用内部的本机函数似乎正在工作。托管函数是一种静态方法 - 我不确定此处是否适用固定,也许 clr 正在终止...
- 确实正在收集托管委托。没有发生处理程序的“覆盖”。我已添加作为答案..不确定要接受什么或这里的 SO 约定是什么...
【问题讨论】:
-
这没什么意义。您不会使用 CreateProcess()“启动方法”。这将创建一个进程,该进程中的任何异常都无法在您的进程中进行代码观察。
-
你对非托管异常的堆栈感兴趣,如果是,那为什么不使用Windbg,它会给你Win32线程的堆栈跟踪。 Infact Windows 调试工具做得很好
-
另外,如果您有相关的非托管代码以及 pdb 文件,请在 VS - Debug - Exceptions 中启用相关的异常类别,它包含 Win32 异常和其他几个类别
-
@MrinalKamboj 这是用于客户端处理崩溃的问题,我已经编辑了这个问题,现在更有意义了吗?
-
@HansPassant 抱歉,我的意思当然是 createthread!显然没有足够的咖啡。这个问题现在已经改进了(我希望)?
标签: c# .net winapi unmanaged unhandled-exception