【C#】多重起動を禁止し起動アプリにパラメータを渡す方法

C#
この記事は約6分で読めます。

多重起動を禁止し起動アプリに引数を渡す方法です。テキストエディタだと定番の処理ですね。プロセス間通信を利用しています。参照設定に System.Runtime.Remoting を追加します。自作エディタもこの方法で実装しています。

サンプルソース

IRemoteObject.cs

多重起動時に実行するメソッドを定義します。

namespace Test {
    public interface IRemoteObject {
        void StartupNextInstance(params object[] parameters);
    }
}

Form1.cs

多重起動を禁止するフォームです。最小化している場合は元に戻します。そしてウィンドウを最前面に表示します。

using System;
using System.Runtime.InteropServices;
using System.Windows.Forms;

namespace Test {
    public partial class Form1 : Form, IRemoteObject {

        [DllImport("user32.dll")]
        public static extern bool IsIconic(IntPtr hWnd);

        [DllImport("user32.dll")]
        public static extern int SetForegroundWindow(IntPtr hWnd);

        [DllImport("user32.dll")]
        public static extern bool ShowWindowAsync(IntPtr hWnd, int nCmdShow);

        // 画面を元の大きさに戻す
        public const int SW_RESTORE = 9;

        /// <summary>
        /// コンストラクタ
        /// </summary>
        public Form1() {
            InitializeComponent();
        }

        /// <summary>
        /// 多重起動時に呼ばれるイベント
        /// </summary>
        /// <param name="parameters"></param>
        /// <returns></returns>
        public void StartupNextInstance(params object[] parameters) {

            // メイン・ウィンドウが最小化されていれば元に戻す
            if (IsIconic(this.Handle)) {
                ShowWindowAsync(this.Handle, SW_RESTORE);
            }

            // メイン・ウィンドウを最前面に表示する
            SetForegroundWindow(this.Handle);

            string[] args = (string[])parameters[0];

            MessageBox.Show("既に起動しています。引数の数:" + args.Length.ToString());
        }
    }
}

Program.cs

初回は普通に起動します。すでに起動している場合は引数を Form1 に渡します。

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

namespace Test {

    static class Program {
        /// <summary>
        /// アプリケーションのメイン エントリ ポイントです。
        /// </summary>
        [STAThread]
        static void Main() {
            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);

            string APP_NAME = Application.ProductName;
            string OBJECT_NAME = "Form1";
            string URL = "ipc://" + Application.ProductName + "/" + OBJECT_NAME;

            bool createdNew = false;
            Mutex mutex = new Mutex(true, APP_NAME, out createdNew);

            // 初回起動時
            if (createdNew) {
                Form1 f = new Form1();

                LifetimeServices.LeaseTime = TimeSpan.Zero;
                LifetimeServices.RenewOnCallTime = TimeSpan.Zero;
                IpcChannel ipc = new IpcChannel(APP_NAME);
                ChannelServices.RegisterChannel(ipc, false);
                RemotingServices.Marshal(f, OBJECT_NAME);

                Application.Run(f);

                // 多重起動時
            } else {
                IRemoteObject remoteObject = (IRemoteObject)RemotingServices.Connect(typeof(IRemoteObject), URL);
                // 引数を渡す
                remoteObject.StartupNextInstance(new object[] { Environment.GetCommandLineArgs() });
            }
        }
    }
}

おわりに

多重起動は Mutex を使う方法がありますが、パラメータを渡せないのでプロセス間通信を利用してみました。

コメント

タイトルとURLをコピーしました