読者です 読者をやめる 読者になる 読者になる

SourceChord

C#とXAML好きなプログラマの備忘録。最近はWPF系の話題が中心です。

アプリの多重起動防止を拡張メソッド一発で行う

C# WPF

以前↓のような方法でアプリの多重起動防止のコードを書きました。
アプリの多重起動を防止する - SourceChord
でも、イベントハンドラをちょこちょこと追加しなきゃいけなくて、もうちょっとスッキリ書けないか考えてみました。

仕組み

AppクラスのStartupとExitのイベントハンドラを使うのは前回と同様ですが、この二つのイベントを拡張メソッド内で設定しています。


この二つのイベントハンドラでは同じmutexインスタンスを使用しなければいけません。
C#には拡張メソッドで、既存のクラスにstaticメソッド相当のものを追加することができますが、プロパティを拡張メソッドのように既存クラスに追加する仕組みはありません。

で、どうしたかというと。。。
ラムダ式でキャプチャしてしまえ!!

拡張メソッドのローカルスコープでMutexクラスのインスタンスを作成して、その変数をラムダ式で書いたイベントハンドラ内でも使用してます。
ラムダ式の中で使用してるので、このmutexローカル変数の寿命が延長されて、二つのイベントハンドラそれぞれで使用できるようにしてます。


拡張メソッドで機能を付加する、ってのも面白いですね。
思いつきで作ったので、若干トリッキーかも、、という気はするけど。。。

コード

SingleInstanceAppExtension.cs
using System.Threading;
using System.Windows;

namespace AppHelper
{
    internal static class SingleInstanceAppExtension
    {
        public static void SetSingleInstance(this Application app, string name)
        {
            Mutex mutex = null;

            app.Startup += (s, e) =>
                {
                    var result = CreateMutex(mutex, name);
                    if (!result)
                    {
                        // すでに起動しているので終了する
                        MessageBox.Show("多重起動はできません。");
                        app.Shutdown();
                    }
                };
            app.Exit += (s, e) =>
                {
                    ReleaseMutex(mutex);
                };
        }

        private static bool CreateMutex(Mutex mutex, string name)
        {
            mutex = new Mutex(false, name);

            if (!mutex.WaitOne(0, false))
            {
                mutex.Close();
                mutex = null;
                return false;
            }

            return true;
        }

        private static void ReleaseMutex(Mutex mutex)
        {
            if (mutex != null)
            {
                mutex.ReleaseMutex();
                mutex.Close();
            }
        }
    }
}


以下のように、Appクラスのコンストラクタで、拡張メソッド一発で多重起動の防止ができるようになります。

App.xaml.cs
// ↓のusingを追加
using AppHelper;


    public partial class App : Application
    {
        public App()
        {
            // Mutex名を指定して、多重起動を防止する。
            this.SetSingleInstance("SingleInstanceApp");
        }
    }