WPFアプリの多重起動を禁止する方法にはいくつかある。本稿ではシステムにグローバルなセマフォを利用してこれを行う方法を紹介する。
対象:.NET 3.0以降
WPFアプリケーションを同時に一つしか起動されたくない場合があるだろう。例えば、アプリケーションを複数起動されると処理が競合して不整合が発生するような場合だ。それには、Windowsシステムにグローバルな(=どのプロセスからもアクセスできる)オブジェクトが利用できる。本稿では、セマフォを使う方法を紹介しよう。
プロセス間の排他制御に利用できる二つの仕組みがある。ミューテックスとセマフォだ。
WPFでは、取得と解放を別のスレッドでも行えるセマフォがお勧めだ。
なお、ミューテックスを使って多重起動を禁止する方法は、Windowsフォーム向けとなるが「.NET TIPS:Windowsアプリケーションの多重起動を禁止するには?」で解説している。
アプリケーションの初期化が始まる前に多重起動を禁止したい場合は、Mainメソッドの冒頭で行う必要が出てくる。しかし、WPFの既定ではMainメソッドの編集ができない。この問題については「.NET TIPS:WPF:Mainメソッドを書き変えるには?[C#/VB]」をご覧いただきたい。
以降では、その記事に従ってMainメソッドを編集可能にしてあるものとして、話を進める。
多重起動の禁止に絞って説明する。
セマフォを作るときに名前を付けると、システムグローバルなセマフォになる。
Semaphoreクラスをインスタンス化するとき、システムにセマフォがまだ存在しないときはセマフォが新たに作られる。すでに存在していた場合は、Semaphoreクラスをインスタンス化するときにその既存のセマフォが利用される。
従って、Semaphoreクラスをインスタンス化したときに、次のようにして多重起動かどうかを判定できる。
なお、セマフォを使用するSemaphoreクラスのインスタンスが一つもなくなったときに、システムはセマフォを破棄する。従って、起動に成功したら、プログラム終了までSemaphoreクラスのインスタンスを保持しておく必要がある(終了時には破棄する)。
Mainメソッドの冒頭でSemaphoreクラスのインスタンスを作り、そのときシステムで新しくセマフォが生成されたかどうかを調べればよい(次のコード)。
Semaphoreクラスのコンストラクター引数のうち、最初の二つは同時に実行できるスレッド数を設定するものだ。多重起動を禁止するためにはそのような制御は必要ないので、適当な数でよい(ここではミューテックスと同等の動作となる「1,1」を指定した)。3番目の引数は、セマフォに付ける名前だ。アプリケーション固有の文字列となるように設定する。最後の引数は、システムで新しくセマフォが生成されたときにtrueとなる。falseだった場合は、すでにシステムにはセマフォが存在していた(=すでにプログラムが実行されていた)ということである。
[STAThread]
public static void Main()
{
const string SemaphoreName = ".NET Tips #1120 (C#)";
bool createdNew;
// Semaphoreクラスのインスタンスを生成し、アプリケーション終了まで保持する
using (var semaphore
= new System.Threading.Semaphore(1, 1, SemaphoreName,
out createdNew))
{
if (!createdNew)
{
// 他のプロセスが先にセマフォを作っていた
MessageBox.Show("すでに起動しています", ".NET TIPS #1120 (C#)",
MessageBoxButton.OK, MessageBoxImage.Hand);
return; // プログラム終了
}
// アプリケーション起動
App app = new App();
app.StartupUri = new Uri("MainWindow.xaml", UriKind.Relative);
app.InitializeComponent();
app.Run();
} // Semaphoreクラスのインスタンスを破棄
}
<STAThread> _
Public Shared Sub Main()
Const SemaphoreName As String = ".NET Tips #1120 (VB)"
Dim createdNew As Boolean
' Semaphoreクラスのインスタンスを生成し、アプリケーション終了まで保持する
Using semaphore _
= New System.Threading.Semaphore(1, 1, SemaphoreName,
createdNew)
If (Not createdNew) Then
' 他のプロセスが先にセマフォを作っていた
MessageBox.Show("すでに起動しています", ".NET TIPS #1120 (VB)",
MessageBoxButton.OK, MessageBoxImage.Hand)
Return ' プログラム終了
End If
' アプリケーション起動
Dim app As Application = New Application()
app.StartupUri = New Uri("MainWindow.xaml", UriKind.Relative)
app.InitializeComponent()
app.Run()
End Using ' Semaphoreクラスのインスタンスを破棄
End Sub
実行してみると次の画像のようになる。
多重起動を禁止するには、ミューテックスかセマフォを使うのが一般的だ。他には、Processクラス(System.Diagnostics名前空間)を使って既存のプロセスを探す方法もある。本稿では、セマフォを使う方法を紹介した。
利用可能バージョン:.NET Framework 3.0以降
カテゴリ:WPF/XAML 処理対象:アプリケーション
使用ライブラリ:Semaphoreクラス(System.Threading名前空間)
関連TIPS:WPF:Mainメソッドを書き変えるには?[C#/VB]
関連TIPS:Windowsアプリケーションの多重起動を禁止するには?
関連TIPS:Visual Basic 2005でWindowsアプリケーションの多重起動を禁止するには?[VS 2005のみ、VB]
関連TIPS:多重起動禁止時に実行中のWindowsアプリケーションを最前面に表示するには?(Processクラスを利用)
Copyright© Digital Advantage Corp. All Rights Reserved.