Locations of visitors to this page


Vista Application Recovery

Onteora Software

Ken Tucker's Blog

About the author

Author Name is someone.
E-mail me Send mail

Recent comments

Disclaimer

The opinions expressed herein are my own personal opinions and do not represent my employer's view in anyway.

© Copyright 2008

Vista Application Recovery

Vista Application Recovery


Ever want to add the ability to recover the user data if your application has crashed. Windows Vista has some nice apis to make this easy.


The RegisterApplicationRestart api tells Vista we would like the app to restart if it crashes or hangs. This api takes two arguments a string which will be the command line argument when the application restarts and RestartFlags. For this example we will tell the app to always restart. Note the app must run 60 seconds before it will restart.



    Enum RestartFlags
        Always = 0
        Cyclical = 1
        NotifySolution = 2
        NotifyFault = 4
        DoNotRestartOnCrash = 8
        DoNotRestartOnHang = 16
        DoNotRestartOnUpdate = 32
    End Enum

    Declare Auto Function RegisterApplicationRestart Lib "kernel32.dll" (ByVal strMessage As String, ByVal RestartOption As RestartFlags) As Integer

RegisterApplicationRestart("Restarted", RestartFlags.Always)



 

The RegisterApplicationRecoveryCallback will allow us to register a function to run if our application crashes or hangs. This will allow us to save the users work before the app terminates. Note that you will not have access to the forms controls but you will have access to the variables. If you want to be able to recover the text in a textbox I would use a variable which is updated in the textboxes textchanged event. Inside the callback function you must tell Vista you are working with the ApplicationRecoveryInProgress function. When the recovery is complete tell Vista with the ApplicationRecoveryFinished function.



    Declare Auto Function RegisterApplicationRecoveryCallback Lib "kernel32.dll" (ByVal cb As App_Recovery_Callback, ByVal Param As String, ByVal PintInterval As Integer, ByVal flags As RestartFlags) As Integer
    Declare Auto Function ApplicationRecoveryInProgress Lib "kernel32.dll" (ByRef Canceled As Boolean) As Integer
    Declare Auto Function ApplicationRecoveryFinished Lib "kernel32.dll" (ByRef Success As Boolean) As Integer

    Delegate Function App_Recovery_Callback(ByVal Param As String) As Integer


    Private Function Recover(ByVal Param As String) As Integer
        Dim b As Boolean
        Using sw As New StreamWriter("Recovered.txt", False)
            ApplicationRecoveryInProgress(b)
            sw.WriteLine(strTextbox)
            ApplicationRecoveryInProgress(b)
            sw.Flush()
            sw.Close()
        End Using
        ApplicationRecoveryFinished(True)

        Return 0
    End Function

One last thing. The .Net framework will catch the error and prevent our recovery callback function from being called. So we need to uncheck the enable application framework box in my projects so we can make the application start with Sub Main. In Sub Main we can Set the UnHandledException Mode to throw exception so Vista will know about the crash


    Public Shared Sub Main()
        Application.SetUnhandledExceptionMode(UnhandledExceptionMode.ThrowException)
        Application.Run(New Form1)
    End Sub


For the sample Application I have a form with a label (label1), textbox (textbox1), 2 buttons (btnCrash an btnHang), and a timer. The timer is used to update the label with how long the app ran. The 2 buttons will hang or crash the app. Here is the code for the sample app. For the app recovery to work run the program without debugging (ctrl+F5).



Imports System.IO

Public Class Form1
    Enum RestartFlags
        Always = 0
        Cyclical = 1
        NotifySolution = 2
        NotifyFault = 4
        DoNotRestartOnCrash = 8
        DoNotRestartOnHang = 16
        DoNotRestartOnUpdate = 32
    End Enum

    Dim strTextbox As String

    Declare Auto Function RegisterApplicationRestart Lib "kernel32.dll" (ByVal strMessage As String, ByVal RestartOption As RestartFlags) As Integer
    Declare Auto Function RegisterApplicationRecoveryCallback Lib "kernel32.dll" (ByVal cb As App_Recovery_Callback, ByVal Param As String, ByVal PintInterval As Integer, ByVal flags As RestartFlags) As Integer
    Declare Auto Function ApplicationRecoveryInProgress Lib "kernel32.dll" (ByRef Canceled As Boolean) As Integer
    Declare Auto Function ApplicationRecoveryFinished Lib "kernel32.dll" (ByRef Success As Boolean) As Integer

    Delegate Function App_Recovery_Callback(ByVal Param As String) As Integer

    Private Sub Timer1_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Timer1.Tick
        Static x As Integer = 0
        Label1.Text = String.Format("App running {0} seconds", x)
        x += 1
    End Sub

    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        If My.Application.CommandLineArgs.Count > 0 Then
            TextBox1.Text = My.Computer.FileSystem.ReadAllText("Recovered.txt")
            ApplicationRecoveryFinished(True)
        End If

        'register app to restart
        RegisterApplicationRestart("Restarted", RestartFlags.Always)

        'setup the Recovery Callback
        RegisterApplicationRecoveryCallback(AddressOf Recover, "Recover Data", 50000, RestartFlags.Always)
        'start a timer to show how long the app has run
        Timer1.Interval = 1000
        Timer1.Enabled = True

    End Sub

    Private Function Recover(ByVal Param As String) As Integer
        Dim b As Boolean
        Using sw As New StreamWriter("Recovered.txt", False)
            ApplicationRecoveryInProgress(b)
            sw.WriteLine(strTextbox)
            ApplicationRecoveryInProgress(b)
            sw.Flush()
            sw.Close()
        End Using
        ApplicationRecoveryFinished(True)

        Return 0
    End Function

    Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnCrash.Click
        Throw New Exception("Crash Me!!!")
    End Sub

    Public Shared Sub Main()
        Application.SetUnhandledExceptionMode(UnhandledExceptionMode.ThrowException)
        Application.Run(New Form1)
    End Sub

    Private Sub TextBox1_TextChanged(ByVal sender As Object, ByVal e As System.EventArgs) Handles TextBox1.TextChanged
        strTextbox = TextBox1.Text
    End Sub

 

    Private Sub btnHang_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnHang.Click
        Do While True
            ' lock me up
        Loop
    End Sub
End Class

 

Daniel Moth and Bart De Smet's have some nice blog entries about using app recovery with c# console apps. You can register your application (a digital signature is required) at the Windows Quality Online Services site to be able to see any error reports sent by your app.

Be the first to rate this post

  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Categories: VB | Vista
Posted by Ken Tucker on Friday, December 08, 2006 11:12 PM
Permalink | Comments (0) | Post RSSRSS comment feed

Related posts

Add comment


(Will show your Gravatar icon)  

  Country flag

[b][/b] - [i][/i] - [u][/u]- [quote][/quote]



Live preview

Thursday, November 20, 2008 11:06 PM