2重起動防止処理を組み込んだWPFアプリでClickOnceの更新と再起動を行う
タイトルでやりたい事を伝えきったので、やり方を説明します。
ClickOnceの更新方法は、探せば見つかると思いますので割愛します。
ClickOnceによる更新は、アプリケーションを再起動しないと行われません。
なので、ClickOnceの更新メソッドを呼び出した後に、以下のコードを実行して、アプリケーションを再起動します。
System.Windows.Forms.Application.Restart(); System.Windows.Application.Current.Shutdown();
一方、WPFアプリケーションで2重起動を防止したい時は、App.xaml.csを編集し、Mutexを使用して以下のように記述すると思います。
参考:WPFでアプリの2重起動を禁止する。 - プログラムを書こう!
private static readonly Mutex Mutex = new Mutex(false, "Mutex名"); private static bool _hasHandle = false; private void OnStartup(object sender, StartupEventArgs e) { _hasHandle = Mutex.WaitOne(0, false); if (!_hasHandle) { MessageBox.Show("2重起動はできません。"); Shutdown(); return; } } private void OnExit(object sender, ExitEventArgs e) { if (_hasHandle) { Mutex.ReleaseMutex(); } Mutex.Close(); }
ここで終了確認をしようと思って、終了プロセスのどこかで、MessageBox.Showによるメッセージ表示を組み込んだとします。
その状態で、ClickOnceの更新+アプリケーションの再起動をすると、終了確認のメッセージに加えて、なんと「2重起動はできません。」というメッセージが表示されてしまいました。
これは終了処理が「終了確認のメッセージを表示する」ところで止まったため、Mutexの解放をする前に新しいアプリケーションを起動しようとして、2重起動防止処理が動いてしまった結果です。
パラメータ等による分岐で、更新時は終了確認のメッセージ表示をやめることで、とりあえず動作するようにはなりました。
しかし、終了処理に時間がかかるようになれば、Mutexの解放をする前に新しいアプリケーションが起動する可能性が残っています。
これを解消するために、最終的にはアプリケーションの起動処理をMutexの解放後にもっていきました。
ViewModel
IsRestart = true; //ViewModelでの終了処理の前に、再起動フラグを設定する Application.Current.Shutdown();
App.xaml.cs
private void OnExit(object sender, ExitEventArgs e) { // Mutexの所有権を保持しているプロセスが実行する if (_hasHandle) { // Mutexを解放します Mutex.ReleaseMutex(); } // Mutexのクローズ処理 // 両方のプロセスで実行される Mutex.Close(); // Mutexの解放後に、新しいアプリケーションを起動する var viewModel = (MainWindowViewModel) _mainWindow.DataContext; if (viewModel.IsRestart) { // 新しいアプリケーションの起動(このメソッドでは、WPFアプリケーションは終了しない) System.Windows.Forms.Application.Restart(); } }
これによって、2重起動防止処理を組み込んだ状態で、ClickOnceの更新と再起動を行うことが出来ました。
以上。