問題

.NETでC#とWPFを使用する( Windowsフォームまたはコンソールではなく)、単一のインスタンスとしてのみ実行できるアプリケーションを作成する正しい方法は何ですか?

私はそれがミューテックスと呼ばれるいくつかの神話的なことと関係があることを知っています。

コードは、ユーザーが2番目のインスタンスを開始しようとしたことをalready-runningインスタンスに通知する必要があります。

  ベストアンサー

Mutexソリューションに関する非常に良い記事です。記事で説明されているアプローチは、2つの理由で有利です。

まず、Microsoft.VisualBasicアセンブリに依存する必要はありません。私のプロジェクトがすでにそのアセンブリに依存している場合、私はおそらく別の答えに示されているアプローチを使用して提唱します。しかし、そうであるように、私はMicrosoft.VisualBasicアセンブリを使用せず、私はむしろ私のプロジェクト

次に、この記事では、ユーザーが別のインスタンスを開始しようとすると、アプリケーションの既存のインスタンスをフォアグラウンドに移動する方法を示しています。これは、ここに記載されている他のMutexソリューションが対処しないという非常に素晴らしいタッチです。


更新

2014年8月1日現在、私が上にリンクした記事はまだアクティブですが、ブログはしばらく更新されていません。それは私が最終的にそれが消えるかもしれないと心配し、それで提唱された解決策を心配します。私は後世のためにここの記事の内容を再現しています。言葉は、 Sanity Free Coding のブログ所有者のみに属しています。

今日私は私のアプリケーションを禁止するいくつかのコードをリファクタリングしたかった 複数のインスタンスを実行することから。

以前は、 System.Diagnostics.Process を使用して プロセスリストのmyapp.exeのインスタンス。これは動作しますが、 多くのオーバーヘッドをもたらします そして もっとクリーンなものが欲しかったのです

私はこれにミューテックスを使うことができることを知っています(しかし、決してそれをしたことはありません 前に)私は自分のコードを切り捨て、私の人生を単純化するように設定しました。

私のアプリケーションメインのクラスでは、 Mutex という静的な名前を作成しました。

 static class Program
{
    static Mutex mutex = new Mutex(true, "{8F6F0AC4-B9A1-45fd-A8CF-72F04E6BDE8F}");
    [STAThread]
    ...
}
 

名前付きミューテックスを持つことで、同期をスタックすることができます 私が見ている魔法である複数のスレッドとプロセス そのために

Mutex.WaitOne には時間を指定するオーバーロードがあります 待ってください。私たちは実際にコードを同期させたくないので (現在使用中かどうかを確認するだけです)オーバーロードを 2つのパラメータ: Mutex.WaitOne(Timespanタイムアウト、bool exitContext)。 wait one は true を返します。 この場合、私たちはまったく待ちたくありません。私たちのミューテックスが 使用し、スキップして移動するので、TimeSpan.Zeroを渡します(待機0 exitContext を true に設定すると、 ロックを解除しようとする前の同期コンテキスト。使用 これにより、Application.Runコードを次のようにラップします。

 static class Program
{
    static Mutex mutex = new Mutex(true, "{8F6F0AC4-B9A1-45fd-A8CF-72F04E6BDE8F}");
    [STAThread]
    static void Main() {
        if(mutex.WaitOne(TimeSpan.Zero, true)) {
            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);
            Application.Run(new Form1());
            mutex.ReleaseMutex();
        } else {
            MessageBox.Show("only one instance at a time");
        }
    }
}
 

だから、私たちのアプリが実行されている場合、WaitOneはfalseを返し、 メッセージボックス。

メッセージボックスを表示する代わりに、少しWin32を利用して 実行中のインスタンスに、誰かがすでにそれが忘れていることを通知する 実行中(他のすべてのウィンドウの上部に移動することによって)。に これを達成するために、私は PostMessage を使ってすべてのカスタムメッセージをブロードキャストしました ウィンドウ(カスタムメッセージは RegisterWindowMessage に登録されました 私の実行中のアプリケーションでは、私のアプリケーションだけが何を知っていることを意味します それは)私の2番目のインスタンスが終了します。実行中のアプリケーションインスタンス その通知を受け取り、それを処理します。そのために、私は 私のメインフォームで WndProc を上回り、私のカスタムを聞いた 通知。その通知を受けたとき、私はフォームを設定しました トップマスプロパティが真実だ

ここに私が終わったものがあります:

  • プログラム.cs
 static class Program
{
    static Mutex mutex = new Mutex(true, "{8F6F0AC4-B9A1-45fd-A8CF-72F04E6BDE8F}");
    [STAThread]
    static void Main() {
        if(mutex.WaitOne(TimeSpan.Zero, true)) {
            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);
            Application.Run(new Form1());
            mutex.ReleaseMutex();
        } else {
            // send our Win32 message to make the currently running instance
            // jump on top of all the other windows
            NativeMethods.PostMessage(
                (IntPtr)NativeMethods.HWND_BROADCAST,
                NativeMethods.WM_SHOWME,
                IntPtr.Zero,
                IntPtr.Zero);
        }
    }
}
 
  • NativeMethods.cs
 // this class just wraps some Win32 stuff that we're going to use
internal class NativeMethods
{
    public const int HWND_BROADCAST = 0xffff;
    public static readonly int WM_SHOWME = RegisterWindowMessage("WM_SHOWME");
    [DllImport("user32")]
    public static extern bool PostMessage(IntPtr hwnd, int msg, IntPtr wparam, IntPtr lparam);
    [DllImport("user32")]
    public static extern int RegisterWindowMessage(string message);
}
 
  • Form1.cs(フロントサイドの部分)
 public partial class Form1 : Form
{
    public Form1()
    {
        InitializeComponent();
    }
    protected override void WndProc(ref Message m)
    {
        if(m.Msg == NativeMethods.WM_SHOWME) {
            ShowMe();
        }
        base.WndProc(ref m);
    }
    private void ShowMe()
    {
        if(WindowState == FormWindowState.Minimized) {
            WindowState = FormWindowState.Normal;
        }
        // get our current "TopMost" value (ours will always be false though)
        bool top = TopMost;
        // make our form jump to the top of everything
        TopMost = true;
        // set it back to whatever it was
        TopMost = top;
    }
}
 

  同じタグがついた質問を見る

c#.netwpfmutex