Windows API Code Packによるアプリ開発 第3回 ~アプリケーションの再起動と修復 その2~

Windows API Code Packによるアプリ開発 [TechED2010 ポストセッション ]第3回アプリケーションの再起動と修復その
2

前回のブログでは、アプリケーションの再起動と修復の仕組みについて説明しました。
今回は、実装方法について説明します。

必要なものはVisual StudioとWindows API Code Packです。
Visual Studioは2010または2008をご用意ください。説明とスクリーンショットにはVisual Studio 2010 Ultimateを使用していますので、Visual Studio 2008やExpress Editionをご使用の場合は、メニューの文言や位置が若干異なる場合があります。
Windows API Code Packについては、本シリーズの第1回の記事をご覧ください。
https://blogs.msdn.com/b/ttanaka/archive/2010/10/04/windows-api-code-pack-teched2010-1.aspx

Windows API Code Packを使用したアプリケーション開発の最初なので、ステップ バイ ステップでサンプルのアプリケーションを作成します。
Visual Studio及びWindows API Code Packがインストールされていることを前提とします。

手順1 : Visual Studioの起動とプロジェクトの作成
ア. Visual Studioを起動します。
イ. メニューより、[ファイル]-[新規作成]-[プロジェクト]を選択して、[新しいプロジェクト]ダイアログを表示させます。
ウ. 左側のインストールされたより[Visual C#]、右側より[WPFアプリケーション]を選択し、プロジェクトに適当な名前をつけて[OK]をクリックしてください。Windowsフォームのほうが使い慣れている方は、Windowsフォーム アプリケーションを選択されてもかまいません。Visual Basicのほうが得意な方は、本記事の最後のほうにあるリンクからTechEDで使用したスライドをダウンロードしていただき、Appendixの部分にあるVisual Basicのソースコードをご参照ください。

手順2 : コントロールの貼り付けボタンとテキストボックスを図のように貼り付けます。それぞれの大きさは適当で構いません。

貼り付けたテキストボックスのAcceptsReturnプロパティにはチェックをつけておきます。
Windowsフォームの場合も、同じようにボタンとテキストボックスを貼り付けます。Windowsフォームの場合は、テキストボックスのMultiLineプロパティをTrueにしておきます。
既存のアプリケーションに再起動と修復の機能を追加する場合は、この手順2を省いて構いません。

手順3 : 参照の追加  ア. メニューの[プロジェクト]-[参照の追加]を選択し、[参照の追加]ダイアログを表示させます。
イ. [参照の追加]ダイアログでは、[参照]タブをクリックして、Windows API Code Packをインストールしたフォルダを表示させます。
ウ. binariesフォルダーの中にあるMicrosoft.WindowsAPICodePack.dllを選択して、[OK]をクリックしてください。
Code Packのバージョン1.01をご使用の場合はDLLファイルが含まれていないので、Code Pack自体を一度ビルドする必要があります。

手順4 : クラッシュさせるコードの追加  ア. 貼り付けたボタンをダブルクリックします。
イ. 以下の青色の部分のコードを追加します。

private void button1_Click(object sender, RoutedEventArgs e){ Environment.FailFast("強制終了");}

Windowsフォームの場合はbutton1_Clickの引数が少し違いますが、気にせず青い部分を追加してください。
このコードを実行すると、アプリケーションを強制的に終了させます。

手順5 : usingの追加ソースコードの先頭のusingが並んでいるところに、以下のコードを追加します。

using Microsoft.WindowsAPICodePack.ApplicationServices;using System.IO;

Visual BasicではImportsに該当します。
最初の一文は、Code Packの再起動と修復の機能を使用するために必要です。
次のSystem.IOは、データを一時保存するためのファイルの読み書きに使用します。

手順6 : フィールドの追加
入力中のデータをメモリ上に保存するためと、クラッシュ時にデータを退避させるファイルのパス名のために、以下のように2つのフィールドを作成します。
青い字の部分を追加してください。

public partial class MainWindow : Window{    private string TextData = ""; private static string RecoveryFile = "c:\\temp\\AppRestartRecoveryDemoData.txt";

    public MainWindow() { InitializeComponent(); }}

Windowsフォームの場合は、Form1クラスの中に青い字のコードを書いてください。
青い部分の最初の一文のTextDataは、入力中の文字を一時的にメモリに入れるために使用します。
アプリケーションの再起動と修復では、クラッシュ時にテキストボックスのようなコントロールに含まれるデータを取得することができません。
テキストボックスに入力された文字列をTextDataに随時保存しておき、そのデータをファイルに書き込みます。
次のRecoveryFileには、クラッシュ時に一時的にデータを保存するファイルのパス名を入れます。
ここでは便宜的にファイル名を固定させていますが、必要に応じて書き込む場所を変えてください。

手順7 : クラッシュ時に呼ばれる修復用メソッドの実装
クラッシュ時に一時ファイルにデータを書き込む修復用のメソッドを追加します。
以下のメソッドを追加してください。

private int RecoveryProcedure(object state){ File.WriteAllText(RecoveryFile, TextData);

    ApplicationRestartRecoveryManager.ApplicationRecoveryFinished(true); return 0;}

このメソッドは、単純にTextDataに記録されている文字列を一時保存用のファイルに書き込んでいるだけです。
ここで使用しているTextDataにはデータが入っていませんので、次の手順でTextDataにデータを入れる部分を実装します。

手順8 : テキストボックスからの読み込み
いったんデザイナーに戻り、テキストボックスに対するイベントハンドラを作成します。
フォームデザイナー上でテキストボックスを選択し、プロパティウィンドウのイベントの一覧からTextChangedを選択し、ダブルクリックしてイベントハンドラを作成します。
イベントハンドラには、以下の青字の一文を追加してください。

private void textBox1_TextChanged(object sender, TextChangedEventArgs e){ TextData = textBox1.Text;}

手順9 : 再起動用コードの登録 / 修復用メソッドの登録 / 再起動時の処理
再起動時用コードの登録、修復用メソッドの登録、再起動時の処理を実装します。
以下の例では、MainWindowのコンストラクタの中に実装しました。実装は、プログラムの起動時に必ず実行する場所であれば、どこでも構いません。
Windowsフォームを使用されているときは、Form1のコンストラクタの中か、プログラム起動時に必ず実行する場所に青字のコードを実装してください。

public MainWindow(){ InitializeComponent();

  // 再起動用コードの登録    ApplicationRestartRecoveryManager.RegisterForApplicationRestart( new RestartSettings("/restart", RestartRestrictions.NotOnReboot | RestartRestrictions.NotOnPatch));

    // 修復用メソッドの登録   RecoveryData data = new RecoveryData(new RecoveryCallback(RecoveryProcedure), null); RecoverySettings settings = new RecoverySettings(data, 0); ApplicationRestartRecoveryManager.RegisterForApplicationRecovery(settings);

    // 起動時の再起動かどうかの判断 // 再起動時にデータを修復するコードの作成    if (System.Environment.GetCommandLineArgs().Length > 1 && System.Environment.GetCommandLineArgs()[1] == "/restart") { if (File.Exists(RecoveryFile)) { textBox1.Text = File.ReadAllText(RecoveryFile); } }}

ここでは、再起動用のコードとして、もしクラッシュ時の再起動であれば /restart というコマンドライン オプションをつけてアプリケーションを起動させるように指定しています。
クラッシュ時に呼ばれる修復用メソッドとして、RecoveryProcedureを登録しています。
万が一クラッシュしてしまったときには、Windows Error ReportingによりRecoveryProcedureが呼び出されます。
再起動時の処理としては、コマンドライン オプションとして /restart というオプションが指定されているかどうかを判断し、もし指定されていれば一時的に保存したファイルからデータを読み込む処理を行っています。

手順10 : プログラムの実行実装は手順9までで終わりです。
しかし、プログラムの実行に2つほど注意事項があります。

まず、このサンプルプログラムは、Visual Studioの開発環境からデバッグ付きで起動させないでください。
デバッグ付きで起動してしまうと、クラッシュをVisual Studioが拾ってしまい、Windows Error Reportingに処理が渡りません。
Visual Studioから起動する場合は、メニューの[デバッグ]-[デバッグなしで開始]を選択してください。

もう一つの注意点として、Windows Error Reportingの仕様として、アプリケーションの起動後60秒間は再起動と修復の機能が働かないという点があります。
サンプルプログラムを起動してボタンをクリックすると、アプリケーションがクラッシュします。
アプリケーションをクラッシュさせるのは、アプリケーション起動後60秒以上経ってからにしてください。

上記の手順1~手順10には、サンプルプログラムとして成り立たせるための手順が含まれます。
手順1、2、4は、既存のアプリケーションにこの機能を追加するときには不要な手順です。
また、その他の手順も、機能を説明する目的のためになるべく少ないコードで記述しています。
あくまでも参照用として取り扱ってください。

次回は、電源の管理について説明します。

[参考資料]
TechEDでのビデオとスライド
https://msdn.microsoft.com/ja-jp/events/ff973814.aspx
内容を早く知りたい方や、デモを確認されたい方は、ビデオをご覧ください。

Windows API Code PackによるWindowsアプリ開発 [TechEDポストセッション]
第1回 :
Windows API Code Packとは第2回 : アプリケーションの再起動と修復 その1
第3回 : アプリケーションの再起動と修復 その2
第4回 : 電源管理
その後は、タスクバーのプログレスバー、アイコン オーバーレイというように進める予定です。

[お知らせ]
Windows 7 アプリ投稿キャンペーンを実施中です。
https://msdn.microsoft.com/ja-jp/windows/jpwin7cp01.aspx
第5回目あたり以降で説明するタスクバーの機能を、既に作っているアプリケーションに追加するだけで、キャンペーンに参加できます。
今なら、簡単なボタンをクリックするだけのアンケートもしていますので、キャンペーンサイトを覗いてみてください。
タスクバーの説明はあと数日お待ちください。

マイクロソフト
田中達彦