Windows の再起動と回復のレシピ


みなさん、こんにちは。Windows 開発統括部の古内です。今日は 2011 年 3 月 21 日に Developing for Windows Blog に投稿された 「 Windows Restart and Recovery Recipe 」 の翻訳をお届けします。

これまで Developing for Windows Blog の記事を数多くご紹介してきました。Windows 7 のタスク バーに関連する記事と、2010 年以降に投稿された記事のほとんどを翻訳したと言っても過言ではありません。しかし、これでしばらく打ち止めとなりそうです。というのも、Developing for Windows Blog には今年の 3 月 24 日以降、新しい記事が投稿されていないからです。Developing for Windows Blog への投稿が再開されたら、また日本語に翻訳して紹介していきたいと思います。


Windows の再起動と回復のレシピ

Windows Vista では、アプリケーションの再起動アプリケーションの回復という、2 つの密接に関連した機能が導入されました。これらの機能は、ハンドルされていない例外や “ハード ハング” などの結果、アプリケーションが予期せず終了した場合の手間をできる限り減らすために設計されています。

アプリケーションの回復は、アプリケーションが予期せず終了したときに失われる可能性のある “文書” などのメモリ内情報を使用しているアプリケーションに適用されます。アプリケーションの再起動は、未保存のデータがあるかどうかにかかわらず、すべてのアプリケーションに対して、特に予期しにくい終了 (DLL の更新やシステムの再起動など) が発生した場合に適用されます。今日、Office 製品 (Microsoft Word など) をはじめとする多くのアプリケーションは、これらの機能を利用しています。アプリケーションに障害が発生した場合でも (ソフトウェアでは、十中八九、どこかで何らかの障害が発生するものですが)、アプリケーションとオペレーティング システムが連携してシームレスな復旧パスを提供するため、ユーザーのフラストレーションがいくらか軽減されます。

基本的に、すべての Windows アプリケーションは、オペレーティング システムで再起動を行うアプリケーションとして登録でき、回復についても、必要に応じて登録を行うことができます。

  • 再起動の登録を行うアプリケーションは、コマンド行の引数を提供します。この引数はアプリケーションに、再起動中であることを通知します。再起動されたアプリケーションが回復対象でもある場合、再起動時に回復データをあらかじめ決められた場所で検索して、未保存のデータを再読み込みできます。
  • 回復の登録を行うアプリケーションは、コールバック関数を提供します。アプリケーションがクラッシュまたはハングすると、オペレーティング システムは別スレッドでこの関数を呼び出します (メイン スレッドでは例外がスローされています)。このコールバック関数は、任意の未保存データをあらかじめ決められた場所に保存できます。しかし、UI スレッドは既に停止しているため、アクセスすることができません。コールバック関数は、永続的に実行できるわけではないことに注意してください。オペレーティング システムにより実行が許可されるのは数秒間のみです。
すばらしい機能のようですが、問題点はあるのでしょうか?

再起動と回復の登録を行うネイティブの Win32 API 呼び出しは、とても簡単に使用できます。Windows API Code Pack には、回復機能、再起動機能の両方について、マネージ ラッパーが用意されています。

ここで、多くの開発者が直面する問題は、回復メソッドで許容される自由度の大きさに起因しています。API は、アプリケーションに障害が発生した際にオペレーティング システムが呼び出すコールバックを必要としますが、その際、開発者は未保存のデータを自由な方法で、自由な場所に書き出すことができます。

ハード ドライブにファイルを書き込むのが一般的な方法ですが、データベースにレコードとして追加したり、ネットワーク上の場所にファイルをアップロードしたり、電子メール メッセージとして送信したり、印刷したり、イベント ログにイベントとして追加したりする場合もあるでしょう。実際のところ、回復コールバックを呼び出し中のアプリケーションは不明な状態にあるため、それらは良い方法とは言えません。回復コールバックを実装する場合は、高速 (コードの実行が迅速) で、利用可能な最低限のリソースのみに依存するソリューションを選択する必要があります。よって、ハード ドライブへの書き込みが最善の方法と思われます。

ハード ドライブにファイルを書き込むことを決定したら、また別の問題が発生します。どのフォルダーを使用すればよいのでしょうか? 開発者の多くは、”現在のディレクトリ” を使用します。開発中はこれで問題ないのですが、アプリケーションが展開され、ユーザーの [Program Files] フォルダーなどにインストールされると、Windows UAC (User Account Control:ユーザー アカウント制御) により、回復コールバック メソッドに対してさらに別の例外が生成され、アプリケーションからそのフォルダーへの書き込みができなくなります。”ユーザーの [AppData] フォルダー (%AppData%) を指定する方が、はるかに賢明です” (これも理想的な選択というわけではありませんが)。

しかし、問題はまだあります。たとえば、どのファイル形式を使用するのか。ファイル名はどうするのか。ファイル名が常に同じ名前にハードコードされるのでない場合、再起動されるアプリケーションでどのようにしてファイルを特定すればよいのか。異なるデータを持つ 2 つのインスタンスを同時に再起動する場合、両者が個別にデータを保存し、再起動時に各自のデータを見つけられるようにするには、どうすればよいのか。幸い、こうした条件をコードに組み込みたいという開発者のためのレシピが用意されています。

Windows の再起動と回復のレシピ (英語) では、マネージ実装 (.NET) とネイティブ実装 (C++) の両方について、上記のすべての問題を解決するライブラリが提供されています。このレシピには、ライブラリの使用方法を示すコード サンプルと、ライブラリのしくみを詳しく説明するドキュメントが含まれています。

このレシピは、再起動機能と回復機能を簡単で使いやすいものにすることを目標に作成されました。

実際に内容をご紹介しましょう。このレシピは、.NET アセンブリ WindowsRecipes.RestartManager として提供されているため、レシピを使用するプロジェクトは、このアセンブリへの参照を追加する必要があります。このアセンブリは、2 つのメソッド (CheckForRestartRegisterForRestartAndRecovery) を含む 1 つのクラス (RestartRecoveryHelper) から成ります。次に、データ モデル クラスを参照する必要があります。Serializable 属性を追加したシリアル化可能な (serializable) 任意のクラスを、保存するデータとして使用できます。その後は、以下のスニペットのように、RegisterForRestartAndRecovery メソッドを呼び出すだけです。

doc = new SampleDocument();
// 必要に応じて doc を初期化する
rrh = new WindowsRecipes.RestartManager.RestartRecoveryHelper<SampleDocument>();
SampleDocument recovereddoc = rrh.CheckForRestart();
if (recovereddoc != null)
{
    doc = recovereddoc;
    //doc の内容を使用して、フォーム上のコントロールの値を設定する
}
rrh.RegisterForRestartAndRecovery("TestHarness",doc,WindowsRecipes.RestartManager.FileType.Xml);

このコードでは、回復メソッドへの登録と、予期しないアプリケーション終了からの回復が行われています。

冒頭の SampleDocument は、デモ目的だけに使用する serializable クラスです。次に、特定の SampleDocument クラス タイプを処理できるヘルパー クラス RestartRecoveryHelper を作成します。保存するデータ オブジェクトの数だけこのようなファイルを作成することも、入れ子にされた 1 つの大きなデータ オブジェクトを作成することもできます。オブジェクトが serializable である限り、いずれの方法も有効です。

次に、予期しない終了が原因でアプリケーションが再起動されたかどうかを確認します。該当する場合、終了前に保存されたデータを取得し、それをアプリケーション ロジックで使用します。たとえば、回復されたデータを使用して、いくつかのコントロールに値を設定できます。これで、回復のパートは終わりです。

次は、アプリケーションが再びクラッシュした場合に備えて、アプリケーションを再起動と回復の対象として登録します。必要な作業は、アプリケーションの名前として使用する文字列と、保存するデータ オブジェクトとして指定した doc と、保存するファイル タイプを渡して、RegisterForRestartAndRecovery メソッドを呼び出すことだけです。

後の処理はレシピに任せます。一時的な回復ファイルは、通常 “C:\Users\<ユーザー名>\AppData\Roaming” にあるローミング対応のアプリケーション データ フォルダーに保存されます。ファイルには必ず一意の名前が付与され、形式はバイナリまたは XML のどちらかを自由に選択できます。これにより、所定のアプリケーションで、さまざまなユーザーおよびクラッシュに対応できるようになります。回復が完了すると、ファイルは削除されます。

こちらのビデオ (英語) では、上記の処理のネイティブ API について、Kate Gregory が詳しく説明しています。

興味のある方は、Windows の再起動と回復のレシピ (英語) で詳しい情報をご参照ください。コードとドキュメントをダウンロードすることもできます。

Comments (0)

Skip to main content