Ressuscitez vos applications avec l’API Application Recovery and Restart

Le 15 avril 2010 à 10:22

Apparu sous Windows Vista et Windows Server 2008, l’API Application Recovery & Restart (ARR) vous permet de « ressusciter » vos applications.

Vous pouvez utiliser cette API dans le cas où vous voulez sauvegarder les données et l’état de votre application avant que celle-ci ne plante complètement (exception, freeze de l’interface… etc).

Pour illustrer cette API, je vais utiliser un exemple basique d’un champ de texte multiligne où des données peuvent être saisies par l’utilisateur et un bouton permettant de simuler le crash de l’application.

En premier lieu nous allons faire un peu d’interop :

internal static class ApplicationRecoveryNativeMethods
{
    internal delegate int ApplicationRecoveryCallback(IntPtr pvParameter);

    [DllImport("kernel32.dll")]
    internal static extern void ApplicationRecoveryFinished
                               ([MarshalAs(UnmanagedType.Bool)] bool success);

    [DllImport("kernel32.dll")]
    [PreserveSig]
    internal static extern uint ApplicationRecoveryInProgress
                      ([Out, MarshalAs(UnmanagedType.Bool)] out bool canceled);

    [DllImport("kernel32.dll", CharSet = CharSet.Unicode)]
    [PreserveSig]
    internal static extern uint RegisterApplicationRecoveryCallback
       (IntPtr pRecoveryCallback, IntPtr param, uint pingInterval, uint flags);

    [DllImport("kernel32.dll")]
    [PreserveSig]
    internal static extern uint RegisterApplicationRestart
      ([MarshalAs(UnmanagedType.BStr)] string commandLineArgs, RestartFlags flags);
}

Ensuite, j’ai déclaré une classe en static qui simplifie l’accès à ces méthodes :

public static class ApplicationRecovery
{
    // Renvoie cette chaîne lors du redémarrage de l'application suite au plantage
    public const string COMMAND_LINE = "{8B2A75FA-FFD6-487A-A27B-3C28A9243C46}";

    public delegate void ApplicationCrashHandler();
    public static event ApplicationCrashHandler OnApplicationCrash;

    private static 
     ApplicationRecoveryNativeMethods.ApplicationRecoveryCallback RecoverApplication;

    public static bool RegisterApplicationRestart()
    {
        uint val = ApplicationRecoveryNativeMethods
                  .RegisterApplicationRestart(COMMAND_LINE, RestartFlags.NONE);
        if (val == 0)
        {
            // On indique le callback
            RecoverApplication = 
            new ApplicationRecoveryNativeMethods.ApplicationRecoveryCallback(Recovery);
            // On enregistre le callback et on indique au système le temps 
           // approximatif de recovery (ici 30sec)
            val = ApplicationRecoveryNativeMethods.RegisterApplicationRecoveryCallback(
                  Marshal.GetFunctionPointerForDelegate(RecoverApplication), 
                  IntPtr.Zero, 30000, 0);
        }
        return val == 0;
    }

    private static int Recovery(IntPtr ptr)
    {
        if (OnApplicationCrash != null)
        {
            OnApplicationCrash();
            // Indique que tout est fini
            ApplicationRecoveryNativeMethods.ApplicationRecoveryFinished(true);
        }
        return 0;
    }
}

Et ensuite dans mon projet exemple, j’utilise la classe ci-dessus :

// On peut aussi tout simplement se baser sur le fichier de recovery
// s'il existe ou non

//bool isRecovery = false;
//if (File.Exists("recovery_xxxxxx.xxx"))
//{
//    isRecovery = true;
//}

bool isRecovery = false;
if (args.Length > 0)
{
    if (args[0] == Recovery.ApplicationRecovery.COMMAND_LINE)
    {
        isRecovery = true;
    }
}

MainWindow win = new MainWindow(isRecovery);

Recovery.ApplicationRecovery.OnApplicationCrash += 
             new Recovery.ApplicationRecovery.ApplicationCrashHandler
                        (win.ApplicationRecovery_OnApplicationCrash);
if (!Recovery.ApplicationRecovery.RegisterApplicationRestart())
{
    MessageBox.Show("Error blabla");
}
SampleApplication.App app = new SampleApplication.App();
app.Run(win);

Note : pour des raisons « pratiques », la restauration et le redémarrage de l’application n’est possible qu’au bout de 60 sec (sinon, si dans le cas où ça plante direct au démarrage, on redémarre en boucle).

Télécharger mon projet exemple ici.

A bientôt,

Mathieu

Ajouter un commentaire

biuquote
  • Commentaire
  • Prévisualiser
Loading

A propos de l'auteur

Mathieu Perrein - Software Solutions Manager, Software Architect, Trainer MCT, MSP de 2010 à 2012.

 

MSP

 

MSP

MSP

 MSPD

MCT

 

Facebook

 

Ce blog est strictement personnel et les opinions exprimées ici n'engagent donc que moi, et pas mon employeur.

Tags

Vous avez désactivé JavaScript ou bien vous possédez une ancienne version d'Adobe Flash Player. Téléchargez la dernière version de Flash Player.