【问题标题】:Get window state of another process获取另一个进程的窗口状态
【发布时间】:2012-06-19 08:54:00
【问题描述】:

如何获取另一个正在运行的进程的窗口状态(maximized, minimized)?

我试过用这个:

Process[] procs = Process.GetProcesses();

        foreach (Process proc in procs)
        {

            if (proc.ProcessName == "notepad")
            {
                MessageBox.Show(proc.StartInfo.WindowStyle.ToString());

            }
        }

但如果进程是MaximizedMinimized,它永远返回Normal

如何解决这个问题?

【问题讨论】:

    标签: c# process


    【解决方案1】:

    您需要通过 P/Invoke 使用 Win32 来检查另一个窗口的状态。下面是一些示例代码:

    static void Main(string[] args)
    {
        Process[] procs = Process.GetProcesses();
    
        foreach (Process proc in procs)
        {
            if (proc.ProcessName == "notepad")
            {
                var placement = GetPlacement(proc.MainWindowHandle);
                MessageBox.Show(placement.showCmd.ToString());
            }
        }
    }
    
    private static WINDOWPLACEMENT GetPlacement(IntPtr hwnd)
    {
        WINDOWPLACEMENT placement = new WINDOWPLACEMENT();
        placement.length = Marshal.SizeOf(placement);
        GetWindowPlacement(hwnd, ref placement);
        return placement;
    }
    
    [DllImport("user32.dll", SetLastError = true)]
    [return: MarshalAs(UnmanagedType.Bool)]
    internal static extern bool GetWindowPlacement(
        IntPtr hWnd, ref WINDOWPLACEMENT lpwndpl);
    
    [Serializable]
    [StructLayout(LayoutKind.Sequential)]
    internal struct WINDOWPLACEMENT
    {
        public int length;
        public int flags;
        public ShowWindowCommands showCmd;
        public System.Drawing.Point ptMinPosition;
        public System.Drawing.Point ptMaxPosition;
        public System.Drawing.Rectangle rcNormalPosition;
    }
    
    internal enum ShowWindowCommands : int
    {
        Hide = 0,
        Normal = 1,
        Minimized = 2,
        Maximized = 3,
    }
    

    定义由 pinvoke.net 提供。

    【讨论】:

    • 在我的例子中,showCmd 始终是原始值,并且保持不变,即使调用了 ShowWindow(showCmd != 1)GetWindowPlacement 仍然在 WINDOWPLACEMENT 结构中返回 showCmd = 1。那么它真的是关于“放置”窗口的那一刻吗?
    • 记得添加对System.Drawing的引用
    【解决方案2】:

    您正在使用 proc.StartInfo,这是不正确的。它不反映目标进程的运行时窗口样式。它只是您可以设置的启动信息,然后可以在启动时传递给进程。

    C# 签名是:

    [DllImport("user32.dll", SetLastError=true)]
    static extern int GetWindowLong(IntPtr hWnd, int nIndex);
    

    您需要使用 p/invoke 并调用 GetWindowLong(hWnd, GWL_STYLE),并将 proc.MainWindowHandle 作为 hWnd 参数传递。

    您可以通过执行以下操作来检查窗口是否最小化/最大化:

    int style = GetWindowLong(proc.MainWindowHandle,  GWL_STYLE);
    if((style & WS_MAXIMIZE) == WS_MAXIMIZE) 
    {
       //It's maximized
    } 
    else if((style & WS_MINIMIZE) == WS_MINIMIZE) 
    {
      //It's minimized
    }
    

    注意:标志的值(WS_MINIMIZE 等)可以在此页面中找到:http://www.pinvoke.net/default.aspx/user32.getwindowlong

    感谢卡卡西指出我们测试结果的错误。

    【讨论】:

    • 不要忘记 C#.NET 在 if/for/while 语句中只接受布尔表达式。如果你想检查来自styleWS_MAXIMIZE 切片值本身,使用& 你应该做(style & WS_MAXIMIZE) == WS_MAXIMIZE
    • 还有必要的(),否则你会得到Operator '&' cannot be applied to operands of type 'int' and 'bool'
    • @marceln:看这张图:thoosje.com/Images/optimizer-screenshot-1.jpg这个窗口状态怎么叫?
    • 我会说这是正常状态。你从winapi得到什么状态?
    • 我无法获得姓名,因为它是 int 而不是 C# enum 类型。只有值。那是349110272。但是 WS_* windows 样式中的正常状态是如何定义的呢?
    【解决方案3】:

    在 Windows PowerShell 中,您可以通过以下代码执行此操作:

    Add-Type -AssemblyName UIAutomationClient
    $prList = Get-Process -Name "<ProcessNamesWhichHaveWindow>"
    $prList | % {
        $ae = [System.Windows.Automation.AutomationElement]::FromHandle($_.MainWindowHandle)
        $wp = $ae.GetCurrentPattern([System.Windows.Automation.WindowPatternIdentifiers]::Pattern)
        echo "Window title: $($_.MainWindowTitle)"
        echo "Window visual state: $($wp.Current.WindowVisualState)"
    }
    

    【讨论】:

      【解决方案4】:

      通过调用 WinAPI IsIconic() / IsZoomed() 可以获得两种窗口状态(最大化/最小化),如下所示:

          [DllImport("user32.dll")]
          [return: MarshalAs(UnmanagedType.Bool)]
          public static extern bool IsIconic(IntPtr hWnd);
      
          [DllImport("user32.dll")]
          public static extern bool ShowWindowAsync(IntPtr hWnd, ShowWindowCommands cmdShow);
      
          if (IsIconic(_helpWindow.MainWindowHandle)) {
              ShowWindowAsync(_helpWindow.MainWindowHandle, ShowWindowCommands.SW_RESTORE);
          }
      

      枚举 ShowWindowCommands 和其他函数的定义取自 www.PInvoke.net

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2015-09-25
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2022-10-14
        相关资源
        最近更新 更多