您可以RegisterApplicationRecoveryCallback改用并重新启动进程。它不会抑制错误报告对话框,但可以在没有用户交互的情况下重新启动应用程序。
using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Reflection;
using System.Threading;
namespace Test
{
class Program
{
public delegate int RecoveryDelegate(IntPtr parameter);
[DllImport("kernel32.dll")]
private static extern int RegisterApplicationRecoveryCallback(
RecoveryDelegate recoveryCallback,
IntPtr parameter,
uint pingInterval,
uint flags);
[DllImport("kernel32.dll")]
private static extern void ApplicationRecoveryFinished(bool success);
private static void RegisterForRecovery()
{
var callback = new RecoveryDelegate(p=>
{
Process.Start(Assembly.GetEntryAssembly().Location);
ApplicationRecoveryFinished(true);
return 0;
});
var interval = 100U;
var flags = 0U;
RegisterApplicationRecoveryCallback(callback,IntPtr.Zero,interval,flags);
}
static void Main(string[] args)
{
RegisterForRecovery();
for (var i = 3; i > 0; i--)
{
Console.SetCursorPosition(0, Console.CursorTop);
Console.Write("Crash in {0}", i);
Thread.Sleep(1000);
}
Environment.FailFast("Crash.");
}
}
}
通过将 ErrorCode 设置为SEM_NOGPFAULTERRORBOX我们正在更改异常过滤行为并强制它传递异常 ( EXCEPTION_CONTINUE_SEARCH) 而不是弹出错误报告对话框 ( EXCEPTION_EXECUTE_HANDLER)。
也许一种正确的方法(实际上可以防止在大多数情况下弹出错误报告对话框)是使用SetUnhandledExceptionFilter并在那里进行恢复,这在 .Net 中大致相当于使用AppDomain.CurrentDomain.UnhandledException. 如果需要捕获 Win32 异常,我们应该通过在 App 配置中添加以下行来启用LegacyCorruptedStatePolicy。
<configuration>
<runtime>
<legacyCorruptedStateExceptionsPolicy enabled="true" />
</runtime>
</configuration>
但是它不会全部捕获(例如 Environment.FastFail 或一些访问冲突),因此我建议同时使用两者。
using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Reflection;
using System.Threading;
namespace Test
{
class Program
{
public delegate int RecoveryDelegate(IntPtr parameter);
[DllImport("kernel32.dll")]
private static extern int RegisterApplicationRecoveryCallback(
RecoveryDelegate recoveryCallback,
IntPtr parameter,
uint pingInterval,
uint flags);
[DllImport("kernel32.dll")]
private static extern void ApplicationRecoveryFinished(bool success);
private static void RegisterForRecovery()
{
var callback = new RecoveryDelegate(p=>
{
Recover();
ApplicationRecoveryFinished(true);
return 0;
});
var interval = 100U;
var flags = 0U;
RegisterApplicationRecoveryCallback(callback,IntPtr.Zero,interval,flags);
}
private static void Recover()
{
//do the recovery and cleanup
Process.Start(Assembly.GetEntryAssembly().Location);
}
private static unsafe void Crash1()
{
var p = (int*)0;
p[0] = 0;
}
private static unsafe void Crash2()
{
var v = 1;
var p =&v;
p -= ulong.MaxValue;
p[0] = 0;
}
static void Main(string[] args)
{
AppDomain.CurrentDomain.UnhandledException +=
new UnhandledExceptionEventHandler((s, e) =>
{
Recover();
Environment.Exit(1);
});
RegisterForRecovery();
for (var i = 3; i > 0; i--)
{
Console.SetCursorPosition(0, Console.CursorTop);
Console.Write("Crash in {0}", i);
Thread.Sleep(1000);
}
//different type of crash
throw new Exception("Crash.");
//Environment.FailFast("Crash.");
//Crash1();
//Crash2();
}
}
}