2009-01-14 60 views
16

我有一個應用程序,一次只能打開一個本身的實例。爲了執行此操作,我使用此代碼:如何關注外國窗口?

 System.Diagnostics.Process[] myProcesses = System.Diagnostics.Process.GetProcesses(); 
     System.Diagnostics.Process me = System.Diagnostics.Process.GetCurrentProcess(); 
     foreach (System.Diagnostics.Process p in myProcesses) 
     { 
      if (p.ProcessName == me.ProcessName) 
       if (p.Id != me.Id) 
       { 
        //if already running, abort this copy. 
        return; 
       } 
     } 
     //launch the application. 
     //... 

它工作正常。我還希望它能夠集中已經運行的副本的形式。也就是說,在返回之前,我想把這個應用程序的另一個實例放到前臺。

我該怎麼做?

回覆:SetForeGroundWindow:

SetForeGroundWindow工作,到一個點:

[System.Runtime.InteropServices.DllImport("user32.dll")] 
    public static extern bool SetForegroundWindow(IntPtr hWnd); 

    //... 
       if (p.Id != me.Id) 
       { 
        //if already running, focus it, and then abort this copy. 
        SetForegroundWindow(p.MainWindowHandle); 
        return; 
       } 
    //... 

這確實帶來窗口前臺,如果沒有最小化它。真棒。 但是,如果窗口被最小化,它將保持最小化。

它需要取消最小化。通過SwitchToThisWindow

解決方案(作品!):

[System.Runtime.InteropServices.DllImport("user32.dll")] 
    public static extern void SwitchToThisWindow(IntPtr hWnd, bool fAltTab); 

    [STAThread] 
    static void Main() 
    { 
     System.Diagnostics.Process me = System.Diagnostics.Process.GetCurrentProcess(); 
     System.Diagnostics.Process[] myProcesses = System.Diagnostics.Process.GetProcessesByName(me.ProcessName); 
     foreach (System.Diagnostics.Process p in myProcesses) 
     { 
      if (p.Id != me.Id) 
      { 
       SwitchToThisWindow(p.MainWindowHandle, true); 
       return; 
      } 
     } 
     //now go ahead and start our application ;-) 
+1

檢查,看看是否窗口IsIconic,如果這樣稱呼的ShowWindow http://msdn.microsoft.com/en-us/library/ms633527(VS.85).aspx 的http:// MSDN。 microsoft.com/en-us/library/ms633548(VS.85)。aspx – cmsjr 2009-01-14 20:25:51

回答

10

我有同樣的問題,SwitchToThisWindow()對我最好。唯一的限制是你必須安裝XP SP1。我玩了SetForegroundWindow,ShowWindow,並且他們在將窗口拉入視圖時都有問題。

+1

請注意,鏈接的MSDN頁面顯示「[此功能不適用於一般用途,可能會在後續版本的Windows中更改或無法使用。]」 – 2011-01-25 10:17:16

0

你可以抓住的處理對象的MainWindowHandle財產,併發送一個WM_USER這個消息你可以解釋爲「其他一些實例想把我帶到前面」。

+0

可以這樣做,雖然看起來很難看。如果SetForegroundWindow不能平移,它可能是一個很好的選擇。 – 2009-01-14 20:18:34

2

完全旁註...

您可以使用

Process.GetProcessesByName(me.ProcessName) 

,而不是遍歷系統中運行的所有進程...

UPDATE

PInvoke這類事情的規則...

3

和OP一樣,我發現只有SetForegroundWindow在窗口最小化時是不夠的。由於我不想使用SwitchToThisWindow,我選擇了ShowWindow,然後是SetForegroundWindow

適合我!

private const SW_SHOWNORMAL = 1 

<DllImport("user32.dll", SetLastError:=True, CharSet:=CharSet.Auto)> _ 
Private Function ShowWindow(ByVal hwnd As IntPtr, ByVal nCmdShow As integer) As Boolean 
End Function 

<DllImport("user32.dll", SetLastError:=True)> _ 
Private Function SetForegroundWindow(ByVal hwnd As IntPtr) As Boolean 
End Function 

Sub SetForeground() 
    Dim processes As Process() = Process.GetProcessesByName("myprocess") 

    For Each p as Process in processes 
     ShowWindow(p.MainWindowHandle, SW_SHOWNORMAL) 
     SetForegroundWindow(p.MainWindowHandle) 
    Next 
End Sub 
2

C#相當於Tom Juergens的答案。對我來說就像一個魅力。

private const int SW_SHOWNORMAL = 1; 

    [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)] 
    private static extern bool ShowWindow(IntPtr hwnd, int nCmdShow); 


    [DllImport("user32.dll", SetLastError = true)] 
    private static extern bool SetForegroundWindow(IntPtr hwnd); 

    public void SetForeground() 
    { 
     Process[] processes = Process.GetProcessesByName("process name"); 

     foreach (Process p in processes) { 
      ShowWindow(p.MainWindowHandle, SW_SHOWNORMAL); 
      SetForegroundWindow(p.MainWindowHandle); 
     } 
    } 
+0

如何簡化上述操作以快速啓動應用程序那已經在運行了? – DeerSpotter 2016-02-05 00:03:25