Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Restart a crashed program with RegisterApplicationRestart without user prompt

I am using the Windows Error Reporting API call RegisterApplicationRestart to register an application to be restarted automatically by WER, when the app crashes or the PC is rebooted.

However, when the app crashes, the default WER dialog pops up ("xyz has stopped responding" / "Do you want to send more information about the problem"), and only after closing this dialog does the program restart.

Is there a way to suppress this dialog box?

If I call SetErrorMode(SEM_NOGPFAULTERRORBOX), then the dialog box is suppressed, as expected, but the restart itself stops working as well.

If I globally suppres the dialog box by changing the registry key HKEY_CURRENT_USER\Software\ Microsoft\Windows\Windows Error Reporting\DontShowUI, I get the same result: the dialog box is suppressed, but the app does not restart either.

I am aware of workarounds like a second watchdog program, but I would really like to solve this as simple as possible with the tools of the Windows Error Reporting API.

like image 536
HugoRune Avatar asked Sep 11 '15 09:09

HugoRune


People also ask

How do you restart program automatically if it crashes in Windows?

Download and run Restart on crash. It's a good idea to already have the app you want to restart running because it makes it easier to add it to the list of apps Restart on Crash needs to restart if it crashes. Click the Add button to add an app for Restart on Crash to monitor.

How do you auto restart an android application after a crash or a force close error?

See below how to do these: Call Thread. setDefaultUncaughtExceptionHandler() in order to catch all uncaught exception, in which case uncaughtException() method will be called. "Force close" will not appear and the application will be unresponsive, which is not a quite good thing.


1 Answers

You can use RegisterApplicationRecoveryCallback instead and Restart the Process. It does not suppress the Error Reporting Dialog but can restart the application without user interaction.

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.");
        }
    }
}

By setting ErrorCode to SEM_NOGPFAULTERRORBOX we are changing the Exception Filtering behavior and force it to pass on the exception (EXCEPTION_CONTINUE_SEARCH) instead of popping the Error Report Dialog (EXCEPTION_EXECUTE_HANDLER).

Maybe a proper way (which actually prevents Error Report Dialog from popping up in most cases) would be to use SetUnhandledExceptionFilter and do the recovery there which in .Net is roughly equivalent to using AppDomain.CurrentDomain.UnhandledException. if weneed to catch Win32 Exceptions, we should Enable LegacyCorruptedStatePolicy by adding following lines to App config.

<configuration>
   <runtime>
      <legacyCorruptedStateExceptionsPolicy enabled="true" />
   </runtime>
</configuration>

however it won't catch all(e.g. Environment.FastFail or some access violations), hence I would suggest to use both.

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();
        }
    }
}
like image 114
user3473830 Avatar answered Oct 04 '22 11:10

user3473830