二重起動を禁止する現在起動しているプロセスを調べる方法VB6では二重起動を禁止するためにApp.PrevInstanceをチェックする方法が一般的でした。これに習い、「VB6のApp.PrevInstanceと同様のことをする」から考えると、次のようなコードですでにアプリケーションが起動しているか調べることができます。ただしこの方法は、プロセス名の同じ別のアプリケーションが存在すると、うまくいかない可能性があります。 '二重起動をチェックする If Diagnostics.Process.GetProcessesByName( _ Diagnostics.Process.GetCurrentProcess.ProcessName).Length > 1 Then 'すでに起動していると判断する MessageBox.Show("多重起動はできません。") End If //二重起動をチェックする if (System.Diagnostics.Process.GetProcessesByName( System.Diagnostics.Process.GetCurrentProcess().ProcessName).Length > 1) { //すでに起動していると判断する MessageBox.Show("多重起動はできません。"); } アプリケーションの二重起動を防ぐには、このようなチェックをエントリポイント等で行い、すでに起動していると判断したらアプリケーションを終了させるようにします。 エントリポイントで二重起動のチェックをする例を以下に示します。エントリポイントについて詳しくは、こちらをご覧ください。 'エントリポイント <STAThread()> _ Shared Sub Main() '二重起動をチェックする If Diagnostics.Process.GetProcessesByName( _ Diagnostics.Process.GetCurrentProcess.ProcessName).Length > 1 Then 'すでに起動していると判断して終了 MessageBox.Show("多重起動はできません。") Return End If Application.Run(New Form1()) End Sub //エントリポイント [STAThread] static void Main() { //二重起動をチェックする if (System.Diagnostics.Process.GetProcessesByName( System.Diagnostics.Process.GetCurrentProcess().ProcessName).Length > 1) { //すでに起動していると判断して終了 MessageBox.Show("多重起動はできません。"); return; } Application.Run(new Form1()); } Mutexを使用する方法VB6以外では、Mutexを使用する方法が一般的です。.NET Frameworkでは、Mutexクラスが用意されていますので、これを使用します。 Mutexクラスを使用して二重起動を禁止するには、次のようにします。ここでもエントリポイントで二重起動をチェックしていますので、エントリポイントが分からないという方は、こちらをご覧ください。 'エントリポイント <STAThread()> _ Shared Sub Main() 'Mutexクラスの作成 '"MyName"の部分を適当な文字列に変えてください Dim mutex As System.Threading.Mutex = New System.Threading.Mutex(False, "MyName") 'ミューテックスの所有権を要求する If mutex.WaitOne(0, False) = False Then 'すでに起動していると判断して終了 MessageBox.Show("多重起動はできません。") Return End If Application.Run(New Form1()) 'ミューテックスを解放する mutex.ReleaseMutex() End Sub //エントリポイント [STAThread] static void Main() { //Mutexクラスの作成 //"MyName"の部分を適当な文字列に変えてください System.Threading.Mutex mutex = new System.Threading.Mutex(false, "MyName"); //ミューテックスの所有権を要求する if (mutex.WaitOne(0, false) == false) { //すでに起動していると判断して終了 MessageBox.Show("多重起動はできません。"); return; } Application.Run(new Form1()); //ミューテックスを解放する mutex.ReleaseMutex(); } さらに、Mutexコンストラクタの別のオーバーロードを使って、次のようにもできます。 'エントリポイント <STAThread()> _ Shared Sub Main() Dim createdNew As Boolean 'Mutexクラスの作成 '"MyName"の部分を適当な文字列に変える Dim mutex As System.Threading.Mutex = _ New System.Threading.Mutex(True, "MyName", createdNew) If createdNew = False Then 'ミューテックスの初期所有権が付与されなかったときは 'すでに起動していると判断して終了 MessageBox.Show("多重起動はできません。") Return End If Application.Run(New Form1()) 'ミューテックスを解放する mutex.ReleaseMutex() End Sub //エントリポイント [STAThread] static void Main() { bool createdNew; //Mutexクラスの作成 //"MyName"の部分を適当な文字列に変える System.Threading.Mutex mutex = new System.Threading.Mutex(true, "MyName", out createdNew); if (createdNew == false) { //ミューテックスの初期所有権が付与されなかったときは //すでに起動していると判断して終了 MessageBox.Show("多重起動はできません。"); return; } Application.Run(new Form1()); //ミューテックスを解放する mutex.ReleaseMutex(); }
補足:.NET Framework 2.0からは、スレッドがMutexを解放せずに終了するとMutexは放棄された状態になり、Mutexを取得する次のスレッドでAbandonedMutexExceptionがスローされるようになりました。また、Mutexが破棄された場合、アプリケーションが強制終了されたことを示す場合があります。そのため、上記のMutexを使ったコードでも最後にReleaseMutexで解放するように書き換えました。書き換える前のコードは以下のようなものでした。
Private Shared _mutex As System.Threading.Mutex 'エントリポイント <STAThread()> _ Shared Sub Main() 'Mutexクラスの作成 '"MyName"の部分を適当な文字列に変えてください _mutex = New System.Threading.Mutex(False, "MyName") 'ミューテックスの所有権を要求する If _mutex.WaitOne(0, False) = False Then 'すでに起動していると判断して終了 MessageBox.Show("多重起動はできません。") Return End If Application.Run(New Form1()) End Sub private static System.Threading.Mutex _mutex; //エントリポイント [STAThread] static void Main() { //Mutexクラスの作成 //"MyName"の部分を適当な文字列に変えてください _mutex = new System.Threading.Mutex(false, "MyName"); //ミューテックスの所有権を要求する if (_mutex.WaitOne(0, false) == false) { //すでに起動していると判断して終了 MessageBox.Show("多重起動はできません。"); return; } Application.Run(new Form1()); }このコードではMutexを静的フィールドとしていますが、これをローカル変数とした場合、うまく行かないことがあります。これは、ガベージコレクションによってローカル変数が破棄されてしまう可能性があるためです。このことは、「A mutex puzzle; single instance of application」で報告されています。 静的フィールドを使う以外に、GC.KeepAliveメソッドを使用する解決法もあります。この場合、Mainメソッドの最後でGC.KeepAliveメソッドを呼び出して、Mutexがガベージコレクションによって破棄されてしまうのを防ぎます。 Visual Studio 2005以降のVB.NETで、Visual Basicアプリケーションモデルを使用する方法Visual Studio 2005からは、VB.NETを使用していれば、二重起動を禁止したアプリケーションを作成するのは簡単です。しかも、同じアプリケーションが後で起動したことを先に起動したアプリケーションで知ることもできますし、後で起動したアプリケーションのコマンドライン引数を取得することもできます。 以下にその手順を示します。
このようにして作成されたアプリケーションでは、すでにアプリケーションが起動しているときにもう一つ起動させようとすると、はじめに起動しているアプリケーションがアクティブになり(ウィンドウが最小化状態のときは、元のサイズに戻されます)、後で起動されたアプリケーションはすぐに終了し、表示されません。
補足:はじめに起動しているアプリケーションをアクティブにしないようにもできます。この方法は、後述します。
後で起動されたアプリケーションのコマンドライン引数を取得するMy.Application.StartupNextInstanceイベントを使うことにより、アプリケーションが二重起動されたことを知ることができます。さらに、後で起動されたアプリケーションに指定されたコマンドライン引数を取得することもできます。 StartupNextInstanceイベントハンドラは、ApplicationEvents.vbファイルに記述するのが一般的のようです(別の場所でも問題ありません)。ApplicationEvents.vbファイルは、プロジェクトプロパティの「アプリケーション」タブにある「アプリケーションイベントの表示」をクリックすることにより表示されます。 以下にApplicationEvents.vbファイルにStartupNextInstanceイベントハンドラを記述した例を示します。ここでは、後で起動されたアプリケーションのコマンドライン引数を表示しています。さらに、StartupNextInstanceEventArgs.BringToForegroundをFalseにすることにより、はじめに起動されたアプリケーションをアクティブにしないようにしています。 Namespace My ' 次のイベントは MyApplication に対して利用できます: ' ' Startup: アプリケーションが開始されたとき、 ' スタートアップ フォームが作成される前に発生します。 ' Shutdown: アプリケーション フォームがすべて閉じられた後に発生します。 ' このイベントは、通常の終了以外の方法でアプリケーションが ' 終了されたときには発生しません。 ' UnhandledException: ハンドルされていない例外がアプリケーションで ' 発生したときに発生するイベントです。 ' StartupNextInstance: 単一インスタンス アプリケーションが起動され、 ' それが既にアクティブであるときに発生します。 ' NetworkAvailabilityChanged: ネットワーク接続が接続されたとき、 ' または切断されたときに発生します。 Partial Friend Class MyApplication Private Sub MyApplication_StartupNextInstance( _ ByVal sender As Object, _ ByVal e As Microsoft.VisualBasic.ApplicationServices. _ StartupNextInstanceEventArgs) _ Handles Me.StartupNextInstance Console.WriteLine("二重起動されました") '後で起動されたアプリケーションのコマンドライン引数を表示 For Each cmd As String In e.CommandLine Console.WriteLine(cmd) Next '先に起動しているアプリケーションをアクティブにしない e.BringToForeground = False End Sub End Class End Namespace
注意:この記事では、基本的な事柄の説明が省略されているかもしれません。初心者の方は、特に以下の点にご注意ください。
|
|
Copyright(C) DOBON!. All rights reserved.
|