如何聚焦外窗?

时间:2009-01-14 19:54:53

标签: c# .net focus

我有一个应用程序,它一次只能打开一个自己的实例。为了强制执行此操作,我使用以下代码:

        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.
        //...

工作正常。我还希望它能够集中已经运行的副本的形式。也就是说,在返回之前,我想把这个应用程序的另一个实例带到前台。

我该怎么做?

Re: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;
                }
    //...

如果未将窗口最小化,则会将窗口置于前台。真棒。 但是,如果窗口IS最小化,它将保持最小化。

需要取消最小化。

通过SwitchToThisWindow解决方案(Works!):

    [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 ;-)

7 个答案:

答案 0 :(得分:10)

我遇到了同样的问题,SwitchToThisWindow()对我来说效果最好。唯一的限制是您必须安装XP sp1。我玩SetForegroundWindow,ShowWindow,他们都把窗口拉到视野中。

答案 1 :(得分: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 :(得分:3)

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);
        }
    }

答案 3 :(得分:2)

我相信你会想要SetForegroundWindow

MSDN Example

答案 4 :(得分:2)

完整的旁注......

您可以使用

Process.GetProcessesByName(me.ProcessName) 

而不是循环遍历系统上运行的所有进程......

<强>更新

PInvoke这类事情的规则......

答案 5 :(得分:0)

您是否可以获取Process对象的MainWindowHandle属性并向其发送一条WM_USER消息,您可以将其解释为“其他一些实例希望将我带到前面”。

答案 6 :(得分:0)

这是桌面应用程序中非常常见的行为,在创建新的WPF应用程序时,我经常必须这样做。所以我创建了一个从Application继承的SingletonApp类:

public class SingletonApp : Application
{
    private static readonly System.Threading.Mutex mutex;
    private static readonly string processName;

    [DllImport("user32.dll")]
    private static extern bool ShowWindow(IntPtr hWnd, int flags);

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

    static SingletonApp()
    {
        processName = Process.GetCurrentProcess().ProcessName;
        mutex = new System.Threading.Mutex(false, $"Local\\{processName}");
    }

    /// <summary>
    /// A base class for application needing to prevent multiple instances
    /// </summary>
    public SingletonApp()
    {
        if (!mutex.WaitOne(0, false))
        {
            // Give focus to existing instance before shutdown
            BringToFront(processName);

            Current.Shutdown();
        }
    }

    public void BringToFront(string processName)
    {
        Process process = Process.GetProcessesByName(processName).FirstOrDefault();

        if (process != null)
        {
            // In case of window is minimized
            ShowWindow(process.MainWindowHandle, 1);     // 1 = Normal

            SetForegroundWindow(process.MainWindowHandle);
        }
    }
}

要使用它,只需从SingletonApp继承,而不是从App.xaml.cs中的Application继承:

public partial class App : SingletonApp

也不要忘记更新App.xaml:

<utils:SingletonApp x:Class="MyApp.App"
             [...]
             xmlns:utils="clr-namespace:MyApp.Utils"
             Startup="App_OnStartup">

有了它,在每个新的桌面客户端中实现此行为变得非常容易。

相关问题