2009-01-14 74 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