簡體   English   中英

檢測應用程序的另一個實例是否已在運行

[英]Detecting if another instance of the application is already running

如果已經有實例運行,我的應用程序在加載時需要表現得略有不同。

我理解如何使用互斥鎖來防止其他實例加載,但這並不能解決我的問題。

例如:

  • 實例1加載,獲取互斥鎖。
  • 實例2加載,無法獲取互斥鎖,知道還有另一個實例。 到現在為止還挺好。
  • 實例1關閉,釋放互斥鎖。
  • 實例3加載,獲取互斥鎖,不知道實例2仍在運行。

有任何想法嗎? 值得慶幸的是,它不需要處理多個用戶帳戶或類似的東西。

(C#,桌面應用程序)

編輯:為了澄清,應用程序不需要限制為單個實例,只需執行一個稍微不同的啟動操作,如果還有另一個實例已經運行。 多個實例都很好(並且是預期的)。

這可能會做你想要的。 它具有很好的附加功能,可以使已經運行的實例前進。

編輯:更新代碼以自動確定應用程序標題。

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;

另一種方法是檢測運行實例,詳見Scott Hanselman的博客

他的例子在第二次嘗試時激活第一個實例。

然而,如果那是你想要的,那么讓第二個實例停下來就不難了。

嘗試使用信號量而不是互斥量

一個好的方法是使用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;
        }
    }

您可以在使用CreateMutex()創建互斥鎖后檢查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
)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM