【お知らせ】プログラミング記事の投稿はQiitaに移行しました。

二重起動禁止と通知

アプリケーションを起動させたときに、既に同一のアプリケーションが起動していればそちらに引数を通知してすぐに終了することで、常に1つのプロセスがすべての処理を行うタイプのアプリケーションがあります。

VB.NETではVBアプリケーションモデルとしてこの種の動作がサポートされているため、簡単に実装することが出来ます。

C#で二重起動を禁止するにはMutexを使った方法が定番ですが、これと.NETリモーティング(プロセス間通信)を組み合わせて同じような動作を実装してみました。以下にコードを示します。

using System;
using System.Runtime.Remoting;
using System.Runtime.Remoting.Channels;
using System.Runtime.Remoting.Channels.Ipc;
using System.Threading;
using System.Windows.Forms;

class Program : MarshalByRefObject
{
    static ListBox listBox;

    [STAThread]
    static void Main(string[] args)
    {
        var mutex = new Mutex(false, Application.ProductName);
        if (mutex.WaitOne(0, false))
        {
            ChannelServices.RegisterChannel(
                new IpcServerChannel(Application.ProductName), true);
            RemotingConfiguration.RegisterWellKnownServiceType(
                typeof(Program), "Program", WellKnownObjectMode.Singleton);
            var f = new Form { Text = "Remoting Server" };
            f.Controls.Add(listBox = new ListBox { Dock = DockStyle.Fill });
            Application.Run(f);
        }
        else
        {
            ChannelServices.RegisterChannel(new IpcClientChannel(), true);
            RemotingConfiguration.RegisterWellKnownClientType(
                typeof(Program), "ipc://" + Application.ProductName + "/Program");
            new Program().StartupNextInstance(args);
        }
        mutex.Close();
    }

    public void StartupNextInstance(string[] args)
    {
        listBox.Invoke((Action)delegate
        {
            listBox.Items.Add("call: " + DateTime.Now.ToString());
        });
    }
}

これはMutexによる二重起動禁止と以下のIPCのサンプルを組み合わせて、一つのプログラムにまとめたものです。

リモーティングにはサーバーとクライアントの区別があります。Mutexによる二重起動判定で処理を振り分けることで、最初に起動したプロセスがサーバーになって、後で起動したプロセスがクライアントになって引数を通知しています。サーバーでの監視はサブスレッドで行われるため、GUIスレッドの更新はControl.Invoke()にクロージャを渡すことで実装しています。