C# 当另一个进程窗口显示ShowInTaskbar=false时,将其置于前台

C# 当另一个进程窗口显示ShowInTaskbar=false时,将其置于前台,c#,winforms,C#,Winforms,我们只希望我们的应用程序在任何时候运行一个实例。因此,在启动时,它会查看应用程序是否正在运行,如果正在运行,它会在主窗口上调用setforegroundindow 这一切都很好。。。大体上 当我们的应用程序启动时,它将显示一个启动屏幕和一个登录表单。这两种形式都有ShowInTaskBar=false 因此,如果您尝试在显示登录表单时启动应用程序的另一个副本,则该登录表单不会出现在最前面 尤其是当用户在任务栏上也看不到任何东西时,他们所想的只是应用程序已经失效,无法启动。没有迹象表明有另一个实例

我们只希望我们的应用程序在任何时候运行一个实例。因此,在启动时,它会查看应用程序是否正在运行,如果正在运行,它会在主窗口上调用setforegroundindow

这一切都很好。。。大体上

当我们的应用程序启动时,它将显示一个启动屏幕和一个登录表单。这两种形式都有ShowInTaskBar=false

因此,如果您尝试在显示登录表单时启动应用程序的另一个副本,则该登录表单不会出现在最前面

尤其是当用户在任务栏上也看不到任何东西时,他们所想的只是应用程序已经失效,无法启动。没有迹象表明有另一个实例正在运行


有办法解决这个问题吗?

代码在这里。即使
ShowInTaskBar
false
,您也应该能够将其置于最前面

    [DllImport("USER32.DLL", CharSet = CharSet.Unicode)]
    public static extern IntPtr FindWindow(String lpClassName, String lpWindowName);

    [DllImport("USER32.DLL")]
    public static extern bool SetForegroundWindow(IntPtr hWnd);

    public static void bringToFront(string title) {
        // Get a handle to the Calculator application.
        IntPtr handle = FindWindow(null, title);

        // Verify that Calculator is a running process.
        if (handle == IntPtr.Zero) {
            return;
        }

        // Make Calculator the foreground application
        SetForegroundWindow(handle);
    }
注意:您应该
FindWindow
使用表单的类而不是名称,因为启动屏幕表单有时没有标题,甚至没有控制框。使用Spy++进行更深入的挖掘

在飞溅上使用
FindWindow
。我想这就是你想要做的——在加载主窗体时将启动屏幕放在前面

FindWindow(null, title);
将找到与查询匹配的第一个窗口。如果另一个窗口使用相同的标题,这可能会导致意外行为


尽管发生这种情况的可能性似乎很小或不可能(单实例应用程序),但这种情况很容易发生。例如,windows资源管理器使用所选目录的名称作为窗口标题(尽管不可见)。现在,如果窗口标题是一个常用术语,或者与应用程序目录的名称匹配,那么这可能是一个问题

我认为这是更好的解决方案,因为它从最小化状态恢复:

public static class WindowHelper
{
    public static void BringProcessToFront(Process process)
    {
        IntPtr handle = process.MainWindowHandle;
        if (IsIconic(handle))
        {
            ShowWindow(handle, SW_RESTORE);
        }

        SetForegroundWindow(handle);
    }

    const int SW_RESTORE = 9;

    [System.Runtime.InteropServices.DllImport("User32.dll")]
    private static extern bool SetForegroundWindow(IntPtr handle);
    [System.Runtime.InteropServices.DllImport("User32.dll")]
    private static extern bool ShowWindow(IntPtr handle, int nCmdShow);
    [System.Runtime.InteropServices.DllImport("User32.dll")]
    private static extern bool IsIconic(IntPtr handle);
}
简单呼叫:

WindowHelper.BringProcessToFront(process);

我正在执行System.Diagnostics.Process.GetProcessesByName调用以获取该进程,然后在Process.MainWindowHandle上调用SetForeGroundIndow。没有ShowInTaskbar,就没有主窗口句柄。FindWindow是解决这个问题的好方法。谢谢这么多的方法可以做到这一点,但这是唯一一个为我工作!请求:如果您添加了-ve点,请给出您的理由/观点。谢谢大家。如果计算器最小化,则无法在Windows 10下工作。问题:设置登录表单的所有者属性不能解决此问题,还是没有任何效果?由于此答案也从最小化状态恢复,因此对其进行升级表决。只需添加到答案,它将无法在调试模式下工作-进程将被设置为活动状态片刻,然后再次隐藏。但如果你只运行你的应用程序,它就可以正常工作。我对这个解决方案投了赞成票,因为它提到了如何使用进程句柄来实现这一点。此外,我喜欢答案的完整性,包括pinvoke的内容。这里有一个比更好的解决方案更好的解决方案:如果计算器最小化,就不能在Windows 10下工作。