在我们平常使用各种各样的软件的时候,特别是在使用软件进行工作的时候,最害怕的事情就是软件突然崩溃,自己的工作成果化为乌有。像在Microsoft offic word2007就提供了这种灾难性回复的支持,例如在你写了一段文档数据后在还没有保存的情况下突然断电或者操作故障导致软件或者操作系统崩溃,那是不是之前我们写的文档就丢失了呢,不是的,在你再次开机重启Microsoft offic word2007后你会惊喜的发现你上次丢失的文件完好无损的展现在您面前,提示您是否保存,看来这种功能还真的很有用,下面我们来看看在基于Visual C#2010开发应用程序遇到灾难性重新启动恢复的演示的开发过程。来在自己的应用程序上定制自己的灾难恢复系统。
1.启动VS2010
2.创建一个AppRestartRecoveryDemo程序,定制下列界面:插入一个menuStrip1,一个statusStrip1,一个timer1
3.具体实现代码如下(解释见代码中注释部分):
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秒后的界面(程序已经“安全”崩溃!)
单击应用程序重新启动恢复->崩溃!后
稍等片刻
之后程序重启后恢复正常,还是之前我编写的文件内容,成功实现了灾难恢复的功能: