在Windows 10中将计算器窗口移到最前面

时间:2020-01-08 17:59:05

标签: c# windows-10 calculator

我想问你一个关于在Windows 10中将计算器窗口置于最前面的问题。我已经测试了很多代码,但实际上没有任何作用。我认为主要的问题是,计算器是“ ApplicationFrameHost”的一部分。 在我的应用程序(C#WinForm)中,如果系统计算器没有运行,我想启动它。如果它正在运行,则即使没有最小化窗口,也要将窗口置于最前面。

public static class WindowHelper
{
    [DllImport("user32.dll")]
    private static extern void keybd_event(byte bVk, byte bScan, uint dwFlags, int dwExtraInfo);
    [DllImport("user32.dll")]
    private static extern bool SetForegroundWindow(IntPtr hWnd);
    [DllImport("user32.dll")]
    private static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);

    private const int ALT = 0xA4;
    private const int EXTENDEDKEY = 0x01;
    private const int KEYUP = 0x02;
    private const int SW_MINIMIZE = 0x06;
    private const int SW_RESTORE = 0x09;

    public static void BringProcessToFront(IntPtr mainWindowHandle)
    {
        // check if window has focus already
        //if (mainWindowHandle == GetForegroundWindow()) return;

        ShowWindow(mainWindowHandle, SW_RESTORE);

        // simulate ALT key down
        keybd_event((byte)ALT, 0x45, EXTENDEDKEY | 0, 0);
        // simulate ALT key up
        keybd_event((byte)ALT, 0x45, EXTENDEDKEY | KEYUP, 0);
        // bring window into foreground
        SetForegroundWindow(mainWindowHandle);
    }
}

private void btnCalc_Click(object sender, EventArgs e)
{
    // get all processes
    System.Diagnostics.Process[] processes = System.Diagnostics.Process.GetProcesses();
    // get ApplicationFrameHost for win10
    System.Diagnostics.Process[] appFH = System.Diagnostics.Process.GetProcessesByName("ApplicationFrameHost");
    IntPtr mWHandle = IntPtr.Zero;


    foreach (System.Diagnostics.Process proc in processes)
    {
        if (proc.ProcessName == "calc" || proc.ProcessName == "Calculator" || proc.ProcessName == "win32calc")
        {
            // non-ApplicationFrameHost case
            mWHandle = proc.MainWindowHandle;

            if (appFH.Length > 0)
            {
                // if ApplicationFrameHost is running, find calculator MainWindowHandle
                foreach (System.Diagnostics.Process app in appFH)
                {
                    if ((app.MainWindowTitle == proc.MainWindowTitle) || (proc.MainWindowTitle.Length == 0))
                        mWHandle = app.MainWindowHandle;
                }
            }
            // bring window to front
            WindowHelper.BringProcessToFront(mWHandle);
            return;
        }
    }
    // calculator was not found, starts new one
    System.Diagnostics.Process.Start("calc");
}

此代码也可以在Windows 7上运行,但对于没有英语本地化版本的10则不能。有一个问题,当最小化计算器时,将无法还原它。

正如我所说,我尝试了很多代码,例如:

public static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
public static extern IntPtr FindWindowEx(IntPtr hwndParent, IntPtr hwndChildAfter, string lpszClass, string lpszWindow);
private static extern bool GetWindowPlacement(IntPtr hWnd, ref WINDOWPLACEMENT lpwndpl);

// this was working to bring focus on already displayed window
WindowHelper.FindWindowEx(app.MainWindowHandle, IntPtr.Zero, "Windows.UI.Core.CoreWindow", null);

主要问题是,我没有找到解决方案,这可能会使非英语本地化窗口上的窗口最小化。

您有一些例子,如何处理? 谢谢。

编辑: 经过一些测试,我确定了为什么无法将此窗口置于最前面。带有en(可能与语言环境无关)的Win7和Win10仍然激活了Calculator,即使未最小化它也是如此。另一方面,将Win10最小化后,第二个Win10进程已暂停(请参阅图片附件)。 enter image description here因此,现在的问题是,如何取消暂停。然后希望可以将窗口移到前面。

2 个答案:

答案 0 :(得分:1)

如果您不是前台窗口,则无法强制使用前台窗口。实际上,有很多条件决定何时可以强制使用前台窗口。来自the docs :(底部适用于您)

系统限制可以设置前景窗口的进程。 仅当以下情况之一时,进程才能设置前台窗口 条件成立:

  • 该过程是前台过程。
  • 该过程由前台过程启动。
  • 该进程收到了最后一个输入事件。
  • 没有前台进程。
  • 该进程正在调试中。
  • 前台进程不是现代应用程序或“开始”屏幕。前景未锁定(请参见LockSetForegroundWindow)
  • 前台锁定超时已到期(请参阅SystemParametersInfo中的SPI_GETFOREGROUNDLOCKTIMEOUT)。
  • 没有菜单处于活动状态。
  • 当用户处于活动状态时,应用程序无法将窗口强制到前台 与另一个窗口一起工作。相反,Windows会闪烁 通知用户的窗口。

答案 1 :(得分:0)

一段时间后(几乎没有其他项目占用),我找到了对我有用的解决方案。

public static class WindowHelper
{
    public static Dictionary<IntPtr, String> appWins;

    public static bool ThreadWindows(IntPtr handle, IntPtr param)
    {
        int size = WindowHelper.GetWindowTextLength(handle);
        if (size > 0)
        {
            StringBuilder strbTitle = new StringBuilder(size + 1);
            WindowHelper.GetWindowText(handle, strbTitle, strbTitle.Capacity);
            if (strbTitle.Length > 0)
            {
                appWins.Add(handle, strbTitle.ToString());
                return true;
            }
        }
        return false;
    }

    public static void BringProcessToFront(IntPtr mainWindowHandle)
    {
        // check if window has focus already
        //if (mainWindowHandle == GetForegroundWindow()) return;

        ShowWindow(mainWindowHandle, SW_RESTORE);

        // simulate ALT key down
        keybd_event((byte)ALT, 0x45, EXTENDEDKEY | 0, 0);
        // simulate ALT key up
        keybd_event((byte)ALT, 0x45, EXTENDEDKEY | KEYUP, 0);
        // bring window into foreground
        SetForegroundWindow(mainWindowHandle);
    }

    //[DllImport("user32.dll")]
    //private static extern IntPtr GetForegroundWindow();

    [DllImport("user32.dll", CharSet = CharSet.Unicode)]
    public static extern int GetWindowTextLength(IntPtr hWnd);
    [DllImport("user32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
    public static extern int GetWindowText(IntPtr hWnd, StringBuilder lpString, int nMaxCount);
    public delegate bool EnumThreadDelegate(IntPtr hWnd, IntPtr lParam);
    [DllImport("user32.dll")]
    public static extern bool EnumThreadWindows(int dwThreadId, EnumThreadDelegate lpfn, IntPtr lParam);
    [DllImport("User32.dll")]
    public static extern IntPtr FindWindowEx(IntPtr hwndParent, IntPtr hwndChildAfter, string lpszClass, string lpszWindow);
    [DllImport("user32.dll")]
    private static extern void keybd_event(byte bVk, byte bScan, uint dwFlags, int dwExtraInfo);
    [DllImport("user32.dll")]
    private static extern bool SetForegroundWindow(IntPtr hWnd);
    [DllImport("user32.dll")]
    private static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);

    private const int ALT = 0xA4;
    private const int EXTENDEDKEY = 0x01;
    private const int KEYUP = 0x02;
    private const int SW_RESTORE = 0x09;
}

private void btnCalc_Click(object sender, EventArgs e)
{
    // get all processes
    System.Diagnostics.Process[] processes = System.Diagnostics.Process.GetProcesses();
    // get ApplicationFrameHost for win10
    System.Diagnostics.Process[] appFH = System.Diagnostics.Process.GetProcessesByName("ApplicationFrameHost");
    IntPtr mWHandle = IntPtr.Zero;

    foreach (System.Diagnostics.Process proc in processes)
    {
        if (proc.ProcessName == "calc" || proc.ProcessName == "Calculator" || proc.ProcessName == "win32calc")
        {
            // save first handle
            mWHandle = proc.MainWindowHandle;

            // if ApplicationFrameHost is running, find calculator MainWindowHandle
            foreach (System.Diagnostics.Process app in appFH)
            {
                // calculator is already running
                if (mWHandle == (IntPtr)0x00)
                {
                    mWHandle = WindowHelper.FindWindowEx(app.MainWindowHandle, IntPtr.Zero, "Windows.UI.Core.CoreWindow", null);
                } else
                {
                    // create new windows dictionary
                    WindowHelper.appWins = new Dictionary<IntPtr, String>();

                    // enumerate all windows in all AFH threads
                    foreach (System.Diagnostics.ProcessThread thread in app.Threads)
                        WindowHelper.EnumThreadWindows(thread.Id, new WindowHelper.EnumThreadDelegate(WindowHelper.ThreadWindows), IntPtr.Zero);

                    // check if proc window was found
                    if (WindowHelper.appWins.ContainsValue(proc.MainWindowTitle))
                    {
                        IntPtr hwnd;
                        // get key from value
                        if ((hwnd = WindowHelper.appWins.First(x => x.Value == proc.MainWindowTitle).Key) != (IntPtr)0)
                            mWHandle = hwnd;
                    }

                    // clear list
                    WindowHelper.appWins.Clear();
                }
            }
            if (mWHandle != (IntPtr)(0x00))
            {
                // bring already running calc to front
                WindowHelper.BringProcessToFront(mWHandle);
                return;
            }
            // do not search for other processes
            break;
        }
    }
    // start new calc instance
    System.Diagnostics.Process.Start("calc");
}

此解决方案与语言环境无关。 感谢所有为我指出正确方向的人。