基於Visual C#2010開發Windows7應用程序遇到災難性重新啓動恢復的演示

在我們平常使用各種各樣的軟件的時候,特別是在使用軟件進行工作的時候,最害怕的事情就是軟件突然崩潰,自己的工作成果化爲烏有。像在Microsoft offic word2007就提供了這種災難性回覆的支持,例如在你寫了一段文檔數據後在還沒有保存的情況下突然斷電或者操作故障導致軟件或者操作系統崩潰,那是不是之前我們寫的文檔就丟失了呢,不是的,在你再次開機重啓Microsoft offic word2007後你會驚喜的發現你上次丟失的文件完好無損的展現在您面前,提示您是否保存,看來這種功能還真的很有用,下面我們來看看在基於Visual C#2010開發應用程序遇到災難性重新啓動恢復的演示的開發過程。來在自己的應用程序上定製自己的災難恢復系統。

1.啓動VS2010

2.創建一個AppRestartRecoveryDemo程序,定製下列界面:插入一個menuStrip1,一個statusStrip1,一個timer1

3.具體實現代碼如下(解釋見代碼中註釋部分):

using System.Windows.Forms; using System.Diagnostics; using System; using System.Threading; using System.Timers; using Microsoft.WindowsAPICodePack.Shell; using System.IO; using Microsoft.WindowsAPICodePack.ApplicationServices; using Microsoft.WindowsAPICodePack.Dialogs; namespace Microsoft.WindowsAPICodePack.Samples.AppRestartRecoveryDemo { public partial class Form1 : Form { private static string AppTitle = "應用程序重啓/恢復的演示-尹成的傑作"; private static FileSettings CurrentFile = new FileSettings(); private static string RecoveryFile = Path.Combine(Path.GetDirectoryName(Application.ExecutablePath), "AppRestartRecoveryDemoData.xml"); private static string DataSeparatorString = "@@@@@@@@@@"; // private bool internalLoad = false; private bool recovered = false; private DateTime startTime; public Form1() { Debug.WriteLine("ARR: Demo started"); InitializeComponent(); Form1.CurrentFile.IsDirty = false; UpdateAppTitle(); RegisterForRestart(); RegisterForRecovery(); statusLabel.Text = "註冊爲重新啓動/恢復申請成功。該應用程序崩潰之前等待60秒。"; //SetupTimerNotifyForRestar設置了一個timer來計時當60秒過去了就開始報警,這表明WER將在程序崩潰後重新啓動, SetupTimerNotifyForRestart(); // 如果我們開始/重新啓動命令行參數 // 然後我們自動重新啓動,並應 // 嘗試恢復之前的會話。 if (System.Environment.GetCommandLineArgs().Length > 1 && System.Environment.GetCommandLineArgs()[1] == "/restart") { recovered = true; RecoverLastSession(System.Environment.GetCommandLineArgs()[1]); } } private void SetupTimerNotifyForRestart() { // 60秒時的響聲已過。 System.Timers.Timer notify = new System.Timers.Timer(60000); notify.Elapsed += new ElapsedEventHandler(NotifyUser); notify.AutoReset = false; // 只有蜂鳴。 notify.Enabled = true; } private void NotifyUser(object source, ElapsedEventArgs e) { statusLabel.Text = "這是\"安全\"崩潰了! (單擊應用程序重新啓動恢復->崩潰!)"; } private void Crash() { Environment.FailFast("ARR Demo intentional crash."); } private void RegisterForRestart() { //註冊自動重新啓動,如果應用程序不是以任何理由重新啓動系統或系統更新而終止。 ApplicationRestartRecoveryManager.RegisterForApplicationRestart( new RestartSettings("/restart", RestartRestrictions.NotOnReboot | RestartRestrictions.NotOnPatch)); Debug.WriteLine("ARR: Registered for restart"); } private void RegisterForRecovery() { //我們使用靜態變量「CurrentFile」,以確定應用程序的當前狀態。 //由於這是正在申請註冊的啓動,在某些情況下,它可能記住這項有意義的初始狀態。 //另一種做法:在做「自動保存」,每次登記回收,並記住保存當前的狀態。 RecoveryData data = new RecoveryData(new RecoveryCallback(RecoveryProcedure), null); RecoverySettings settings = new RecoverySettings(data, 0); ApplicationRestartRecoveryManager.RegisterForApplicationRecovery(settings); Debug.WriteLine("ARR: Registered for recovery"); } // 這種方法是調用WER private int RecoveryProcedure(object state) { Debug.WriteLine("ARR: Recovery procedure called!!!"); PingSystem(); // 在這裏做恢復工作。 //WER恢復的信號工作仍在進行中。 //寫入文件的內容,以及一些其他我們需要的數據。 File.WriteAllText(RecoveryFile, string.Format("{1}{0}{2}{0}{3}", DataSeparatorString, CurrentFile.Filename, CurrentFile.IsDirty, CurrentFile.Contents)); Debug.WriteLine("File path: " + RecoveryFile); Debug.WriteLine("File exists: " + File.Exists(RecoveryFile)); Debug.WriteLine("Application shutting down..."); ApplicationRestartRecoveryManager.ApplicationRecoveryFinished(true); return 0; } //此方法被調用以確保定期WER恢復仍在進行中。 private void PingSystem() { // Find out if the user canceled recovery. bool isCanceled = ApplicationRestartRecoveryManager.ApplicationRecoveryInProgress(); if (isCanceled) { Console.WriteLine("Recovery has been canceled by user."); Environment.Exit(2); } } private void RecoverLastSession(string command) { if (!File.Exists(RecoveryFile)) { MessageBox.Show(this, string.Format("Recovery file {0} does not exist", RecoveryFile)); internalLoad = true; textBox1.Text = "Could not recover the data. Recovery data file does not exist"; internalLoad = false; UpdateAppTitle(); return; } // Perform application state restoration // actions here. //執行應用程序狀態恢復的方法 string contents = File.ReadAllText(RecoveryFile); CurrentFile.Filename = contents.Remove(contents.IndexOf(Form1.DataSeparatorString)); contents = contents.Remove(0, contents.IndexOf(Form1.DataSeparatorString) + Form1.DataSeparatorString.Length); CurrentFile.IsDirty = contents.Remove(contents.IndexOf(Form1.DataSeparatorString)) == "True" ? true : false; contents = contents.Remove(0, contents.IndexOf(Form1.DataSeparatorString) + Form1.DataSeparatorString.Length); CurrentFile.Contents = contents; // 給文本賦值 textBox1.Text = CurrentFile.Contents; // 更新標題 UpdateAppTitle(); // 重置我們的變量,以便下次標題更新我們不顯示「恢復」文本 recovered = false; } private void exitToolStripMenuItem_Click(object sender, EventArgs e) { PromptForSave(); Application.Exit(); Close(); } private void openToolStripMenuItem_Click(object sender, EventArgs e) { PromptForSave(); CommonOpenFileDialog cfd = new CommonOpenFileDialog(); cfd.Filters.Add(new CommonFileDialogFilter("Text files", ".txt")); CommonFileDialogResult result = cfd.ShowDialog(); if (result == CommonFileDialogResult.OK) { internalLoad = true; Form1.CurrentFile.Load(cfd.FileName); textBox1.Text = CurrentFile.Contents; internalLoad = false; UpdateAppTitle(); } } private void PromptForSave() { if (Form1.CurrentFile.IsDirty) { //請用戶保存。 DialogResult dr = MessageBox.Show(this, "Current document has changed. Would you like to save?", "Save current document", MessageBoxButtons.YesNoCancel); if (dr == DialogResult.Cancel) return; else if (dr == DialogResult.No) { // 什麼也不做 } else if (dr == DialogResult.Yes) { // 當前文件是否有一個名字? if (string.IsNullOrEmpty(Form1.CurrentFile.Filename)) { CommonSaveFileDialog saveAsCFD = new CommonSaveFileDialog(); saveAsCFD.Filters.Add(new CommonFileDialogFilter("Text files", ".txt")); if (saveAsCFD.ShowDialog() == CommonFileDialogResult.OK) { Form1.CurrentFile.Save(saveAsCFD.FileName); UpdateAppTitle(); } else return; } else { // 暫時保存 Form1.CurrentFile.Save(CurrentFile.Filename); UpdateAppTitle(); } } } } private void textBox1_TextChanged(object sender, EventArgs e) { if (!internalLoad && Form1.CurrentFile != null) { Form1.CurrentFile.IsDirty = true; Form1.CurrentFile.Contents = textBox1.Text; UpdateAppTitle(); } } private void saveToolStripMenuItem_Click(object sender, EventArgs e) { // 當前文件是否有一個名字? if (string.IsNullOrEmpty(Form1.CurrentFile.Filename)) { CommonSaveFileDialog saveAsCFD = new CommonSaveFileDialog(); saveAsCFD.Filters.Add(new CommonFileDialogFilter("Text files", ".txt")); if (saveAsCFD.ShowDialog() == CommonFileDialogResult.OK) { Form1.CurrentFile.Save(saveAsCFD.FileName); UpdateAppTitle(); } else return; } else { // 暫時保存 Form1.CurrentFile.Save(Form1.CurrentFile.Filename); UpdateAppTitle(); } } private void UpdateAppTitle() { string dirtyState = ""; if (Form1.CurrentFile.IsDirty) dirtyState = "*"; if (string.IsNullOrEmpty(Form1.CurrentFile.Filename)) this.Text = string.Format("{0}{1} - {2}", "Untitled", dirtyState, AppTitle); else this.Text = string.Format("{0}{1} - {2}", Path.GetFileName(Form1.CurrentFile.Filename), dirtyState, AppTitle); if (recovered) this.Text += " (RECOVERED FROM CRASH)"; } private void crashToolStripMenuItem_Click(object sender, EventArgs e) { Crash(); } private void undoToolStripMenuItem_Click(object sender, EventArgs e) { textBox1.Undo(); } private void cutToolStripMenuItem1_Click(object sender, EventArgs e) { textBox1.Cut(); } private void copyToolStripMenuItem1_Click(object sender, EventArgs e) { textBox1.Copy(); } private void pasteToolStripMenuItem1_Click(object sender, EventArgs e) { textBox1.Paste(); } private void selectAllToolStripMenuItem1_Click(object sender, EventArgs e) { textBox1.SelectAll(); } private void aboutToolStripMenuItem_Click(object sender, EventArgs e) { MessageBox.Show(this, "重新啓動和恢復的應用演示", "Windows API的.NET Framework代碼包"); } private void timer1_Tick(object sender, EventArgs e) { TimeSpan span = DateTime.Now - startTime; timerLabel.Text = string.Format("App running for {0}s", (int)span.TotalSeconds); } private void Form1_Load(object sender, EventArgs e) { startTime = DateTime.Now; } } }

4.啓動調試運行後效果如下圖:

60秒後的界面(程序已經「安全」崩潰!)

單擊應用程序重新啓動恢復->崩潰!後

稍等片刻

之後程序重啓後恢復正常,還是之前我編寫的文件內容,成功實現了災難恢復的功能: