web-dev-qa-db-ja.com

1つのアプリケーションインスタンスのみを保証する

重複の可能性:
単一インスタンスアプリケーションを作成する正しい方法は何ですか?

Winformsアプリがあり、次のコードでスプラッシュスクリーンを起動します。

Hide();
        bool done = false;
        // Below is a closure which will work with outer variables.
        ThreadPool.QueueUserWorkItem(x =>
                                  {
                                      using (var splashForm = new SplashScreen())
                                      {
                                          splashForm.Show();
                                          while (!done)
                                              Application.DoEvents();
                                          splashForm.Close();
                                      }
                                  });

        Thread.Sleep(3000);
        done = true;

上記はメインフォームの分離コードにあり、loadイベントハンドラーから呼び出されます。

ただし、アプリケーションのインスタンスが一度に1つだけ読み込まれるようにするにはどうすればよいですか?メインフォームのロードイベントハンドラーで、プロセスリストがシステム上にあるかどうかを(GetProcessesByName(...)を介して)確認できますが、より良い方法はありますか?

.NET 3.5の使用。

23
GurdeepS

GetProcessesByNameは、別のインスタンスが実行されているかどうかを確認するのに時間がかかります。最も速くてエレガントな方法はmutexを使用することです:

[STAThread]
    static void Main()
    {
        bool result;
        var mutex = new System.Threading.Mutex(true, "UniqueAppId", out result);

        if (!result)
        {
            MessageBox.Show("Another instance is already running.");
            return;
        }

        Application.Run(new Form1());

        GC.KeepAlive(mutex);                // mutex shouldn't be released - important line
    }

また、提示したコードが最善の方法ではないことも覚えておいてください。コメントの1つで助言されたように、ループでDoEvents()を呼び出すことは最善の考えではありません。

60
static class Program
{
    // Mutex can be made static so that GC doesn't recycle
    // same effect with GC.KeepAlive(mutex) at the end of main
    static Mutex mutex = new Mutex(false, "some-unique-id");

    [STAThread]
    static void Main()
    {
        // if you like to wait a few seconds in case that the instance is just 
        // shutting down
        if (!mutex.WaitOne(TimeSpan.FromSeconds(2), false))
        {
            MessageBox.Show("Application already started!", "", MessageBoxButtons.OK);
            return;
        }

        try
        {
            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);
            Application.Run(new Form1());
        }
        finally { mutex.ReleaseMutex(); } // I find this more explicit
    }
}

Some-unique-idについての注意->これはマシン上で一意である必要があるため、会社名/アプリケーション名などを使用します。

編集:

http://sanity-free.org/143/csharp_dotnet_single_instance_application.html

23
Denis Biondic