WPFアプリケーション再起動（力技）

# はじめに

アプリケーションソフトを自ら再起動させたいことがある．

Windowsフォームのアプリケーションであれば，

```cpp
Application.Restart();
```

で，いけるらしい．
WPFアプリケーションで，これは動かない．```Restart()```メソッドは存在しない．Web検索でいろいろ調べてみたがどうも無理っぽい．
でも，どうにかして実現したい．

時間がない人はまとめへ．

# 簡単な実験

WPFアプリケーションを終了させるだけなら，さほど難しくない．次のように書くだけだ．

```csharp
Application.Current.Shutdown();
```

このあとに続けてコードを書くことができるので，試しにアプリの開始を書いてみる．

```csharp
Application.Current.Shutdown();
Application.Current.Run();
```

これは```Run()```が実行されたときにInvalidOperationExceptionが発生する．
そもそも，使い方を理解せずに適当に書いただけなので，これは良くない．

```Shutdown()``` メソッドは引数を取る事ができ，これは終了コードとして設定される．

```csharp
Application.Current.Shutdown(1);
```

これを実行して終了させると，VisualStudioの出力ウィンドウには次のように表示される．

> プログラム '[0x****] WpfApplication.vshost.exe' はコード 1 (0x1) で終了しました。

確かに，指定した終了コードが得られている．

# 再起動させる
実験を踏まえて，何とかして再起動させる．

## 構想
実験から，少なくとも終了コードを指定して終了できることだけは分かった．
再起動させたいWPFアプリケーションを，他のプロセスから動かして，終了したらもう一度起動させればよいのではないか？
これをやるには新たにコンソールアプリを作って・・・・・・だとめんどすぎる・・・・・・気がする．
内容的にはバッチファイルでいいじゃん！

## 実装
こんなバッチファイルを作ってみた．

```bat:WpfApplication.bat
@echo off
:Start
start /wait WpfApplication.exe
if %ERRORLEVEL% == 1 (
    goto Start
)
exit
```

WpfApplication.exeの終了コードは通常，0が返る．
ユーザが特定の操作を行ったときのみ，終了コードが1となり，WpfApplication.exeが再起動される．

## 実験
試してみると思い通り動く！！！

・・・・・・動くけど，コマンドプロンプトが表示されるのがちょっと邪魔．
このコマンドプロンプトを閉じてしまうと，再起動されなくなる．

## コマンドプロンプト非表示
調べると，コマンドプロンプトを非表示にするには，VBSを使えばいいらしい．

```bat:WpfApplication.vbs
CreateObject("WScript.Shell").Run "WpfApplication.bat",0
```
[人力検索はてな](http://q.hatena.ne.jp/1148004776)でみかけたコードを使った．

## 再実験
WpfApplication.vbsを実行すると，コマンドプロンプトは表示されない！ちゃんとバッチファイルも動いてる！

# C#で再起動させる
やっぱり，バッチファイルはちょっとアレじゃね？
VisualStudioを持ってない人でも実装できる簡易な手法ではあるのだが・・・・・・．
せっかくC#で書いてるんだから，やはりC#で実現したい．

## 構想
さっきのバッチ処理を全部C#で書くだけ．

## 実装
C#で書くのはめんどくさい気がしていたが，気のせいだったぜ！

```csharp:Program.cs
using System.Diagnostics;

namespace WpfApplicationWrapper
{
    class Program
    {
        static void Main(string[] args)
        {
            Process proc;
            do
            {
                proc = Process.Start(@"WpfApplication.exe");
                proc.WaitForExit();
            } while (proc.ExitCode > 0);
        }
    }
}
```

プロセスを動かして，終了するまで待って，終了コードを見て再起動するかどうかを判別．
本当にやってることはバッチ処理とまったく同じだ．

このプロジェクト自体はコンソールアプリケーションで作るのだが，こちらでもコマンドプロンプトが表示される問題が出てくる．しかし，この解決は，簡単．
プロジェクトのプロパティで「出力の種類」を「コンソールアプリケーション」から「Windowsアプリケーション」に変更するだけだ．

## 実験
試してみると思い通り動く！！！

# まとめ
WPFアプリケーションを力技で再起動させることに成功した．

方法は2種．バッチファイルを使う手法と，C#で新たな実行ファイルを作る手法だ．

バッチファイルを使う手法では，アプリケーションソフトのほかに，.batファイルと.vbsファイルの2個が必要となった．ちゃんとやれば1個ですむかもしれないが，そこまでやる気はない．

C#で新たな実行ファイルを作る手法では，先のバッチファイルでやった内容を，そのままC#で置き換えただけだ．作業量としては，バッチファイルを作るのとさほど変わらない．

どちらの手法を使っても，同様の動作をして目的どおり，WPFアプリを再起動できた．個人的には，C#で組んでるなら，バッチファイルを使うより，C#で実現する方がおすすめだ．VisualStudioがそのまま使えるし．

論理的にはアプリケーションソフト内部で使っているオブジェクトとか変数とかをちゃんと初期化できれば，わざわざ再起動なんてしなくて済むはずだ．
しかしながら，その下の階層で呼び出される*.dllの作りの悪さとかと絡んで，そうもいかないことがある．

もしかしたら，ちゃんとプログラムを組めば自力で再起動できるかもしれないが，あるなら教えて欲しい．

## 力技で再起動させる手順
力技で再起動させる手順は次の通り．
WPFアプリケーションを作るのはバッチファイルを使う手法でもC#で新たな実行ファイルを作る手法でも共通だ．
まとめとしては，C#で新たな実行ファイルを作る手法だけを改めて書いておく．

### WPFアプリケーションを作る
WpfApplication.exeを作る．
多分，再起動させたいときは特定の手順を踏んだときだけなので，再起動させるときは終了コードを0以外に設定する．
アプリケーションを終了コード1を指定して終了させるコードは次のとおり．

```csharp
Application.Current.Shutdown(1);
```

### 再起動させるための新たなアプリケーションを作る
終了コードが1のときのみ，再起動させる．C#で実装すると，次のような感じになる．

```csharp:Program.cs
using System.Diagnostics;

namespace WpfApplicationWrapper
{
    class Program
    {
        static void Main(string[] args)
        {
            Process proc;
            do
            {
                proc = Process.Start(@"WpfApplication.exe");
                proc.WaitForExit();
            } while (proc.ExitCode > 0);
        }
    }
}
```

### 実行
ユーザはWpfApplicationWrapper.exeを実行するだけ．WpfApplication.exeが普通に起動する．
WpfApplication.exeで特定の操作をしたときだけ終了コード1が返され，WpfApplicationWrapperはWpfApplication.exeをもう一度実行する．通常は終了コードが0であり，そのまま終了される．