13

すでにインスタンスが実行されている場合、アプリケーションはロード時に少し異なる動作をする必要があります。

ミューテックスを使用して追加のインスタンスが読み込まれないようにする方法は理解していますが、それでも問題は解決しません。

例えば:

  • インスタンス 1 がロードされ、mutex が取得されます。
  • インスタンス 2 がロードされ、mutex を取得できず、別のインスタンスがあることがわかります。ここまでは順調ですね。
  • インスタンス 1 が閉じ、ミューテックスを解放します。
  • インスタンス 3 が読み込まれ、mutex が取得されますが、インスタンス 2 がまだ実行中であることはわかりません。

何か案は?ありがたいことに、複数のユーザー アカウントなどを扱う必要はありません。

(C#、デスクトップ アプリケーション)

編集:明確にするために、アプリケーションを単一のインスタンスに制限する必要はありません。別のインスタンスが既に実行されている場合は、わずかに異なる起動アクションを実行するだけです。複数のインスタンスは問題ありません (期待されます)。

4

5 に答える 5

12

これはおそらくあなたが望むことをするでしょう。すでに実行中のインスタンスを転送するという優れた追加機能があります。

編集:アプリケーションのタイトルを自動的に決定するようにコードを更新しました。

using System;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Runtime.InteropServices;

static void Main()
{
    if (!EnsureSingleInstance())
    {
        return;
    }

    //...
}

static bool EnsureSingleInstance()
{
    Process currentProcess = Process.GetCurrentProcess();

    var runningProcess = (from process in Process.GetProcesses()
                          where
                            process.Id != currentProcess.Id &&
                            process.ProcessName.Equals(
                              currentProcess.ProcessName,
                              StringComparison.Ordinal)
                          select process).FirstOrDefault();

    if (runningProcess != null)
    {
        ShowWindow(runningProcess.MainWindowHandle, SW_SHOWMAXIMIZED);
        SetForegroundWindow(runningProcess.MainWindowHandle);

        return false;
    }

    return true;
}

[DllImport("user32.dll", EntryPoint = "SetForegroundWindow")]
private static extern bool SetForegroundWindow(IntPtr hWnd);

[DllImport("user32.dll")]
private static extern Boolean ShowWindow(IntPtr hWnd, Int32 nCmdShow);

private const int SW_SHOWMAXIMIZED = 3;
于 2010-07-06T21:07:58.023 に答える
2

もう 1 つのアプローチは、実行中のインスタンスを検出することです。詳しくは、Scott Hanselman のブログを参照してください。

彼の例では、2 番目のインスタンスが試行されると、最初のインスタンスがアクティブになります。

ただし、必要に応じて 2 番目のインスタンスを停止させることは難しくありません。

于 2010-07-06T21:07:29.077 に答える
1

ミューテックスの代わりにセマフォを使用してみてください

于 2010-07-06T21:03:04.157 に答える
0

GetLastError()でミューテックスを作成した後、簡単に確認できますCreateMutex()か?が返されるERROR_ALREADY_EXISTS場合は、アプリケーションの別の実行中のインスタンスがあります。

http://msdn.microsoft.com/en-us/library/ms682411%28VS.85%29.aspxによると、

ミューテックスが名前付きミューテックスであり、この関数呼び出しの前にオブジェクトが存在していた場合、戻り値は既存のオブジェクトへのハンドルであり、GetLastErrorはERROR_ALREADY_EXISTSを返し、bInitialOwnerは無視され、呼び出し元のスレッドには所有権が付与されません。ただし、呼び出し元のアクセス権が制限されている場合、関数はERROR_ACCESS_DENIEDで失敗するため、呼び出し元はOpenMutex関数を使用する必要があります。

編集:これがC#/。Netの質問であることに気づきました。ごめんなさい。

.Netでは、createdNewフラグを返すMutexコンストラクターを使用します。http : //msdn.microsoft.com/en-us/library/bwe34f1k%28VS.80%29.aspx

public Mutex (
    bool initiallyOwned,
    string name,
    out bool createdNew
)
于 2010-07-06T21:48:19.033 に答える
0

Sandor ソリューションを使用し、WMI を使用してプロセス リストを取得することをお勧めします。C#: 実行中のプロセスのフル パスを取得するにはどうすればよいですか? (ジェフの解決策)。そうすれば、他の実行中のインスタンスがパスとリモート ターミナル セッション ID で一致するかどうかを確認することもできます。

    static bool EnsureSingleInstance()
    {
        Process currentProcess = Process.GetCurrentProcess();

        var wmiQueryString = "SELECT ProcessId, ExecutablePath, CommandLine FROM Win32_Process";
        using (var searcher = new ManagementObjectSearcher(wmiQueryString))
        using (var results = searcher.Get())
        {
            var query = from p in Process.GetProcesses()
                        join mo in results.Cast<ManagementObject>()
                        on p.Id equals (int)(uint)mo["ProcessId"]
                        select new
                        {
                            Process = p,
                            Path = (string)mo["ExecutablePath"],
                            CommandLine = (string)mo["CommandLine"],
                        };

            var runningProcess = (from process in query
                                  where
                                    process.Process.Id != currentProcess.Id &&
                                    process.Process.ProcessName.Equals(
                                      currentProcess.ProcessName,
                                      StringComparison.Ordinal) &&
                                      process.Path == currentProcess.MainModule.FileName &&
                                      process.Process.SessionId == currentProcess.SessionId
                                  select process).FirstOrDefault();

            return runningProcess == null;
        }
    }
于 2014-12-05T09:14:59.860 に答える