【问题标题】:How to get the process Id of not responding foreground app?如何获取不响应前台应用程序的进程ID?
【发布时间】:2016-07-28 06:10:04
【问题描述】:

我有一个监控用户当前正在工作的窗口的进程(GetForegroundWindow)。要通过 HWND 获取进程 ID,我使用 GetWindowThreadProcessId。但是,如果前台应用程序挂起,我会得到Desktop Window Manager - dwm.exe 的进程ID。我可以确定应用程序是否被IsHungAppWindow 挂起。 但是如何获取前台挂起应用的真实进程ID?

【问题讨论】:

  • 您是否可以选择使用System.Diagnostics.Process 类?
  • @user3185569,System.Diagnostics.Process 在我的情况下有什么好处?
  • 你试图过滤掉dwm.exe?
  • @ArtavazdBalayan 您可以使用它来查询没有响应的进程并获取它们的进程ID。
  • @user3185569,不清楚。你能举一些例子吗?

标签: c# windows winapi pinvoke


【解决方案1】:

我们可以使用 user32.dll HungWindowFromGhostWindow 中未记录的方法从ghost句柄中获取真实的窗口句柄(如果windows被挂起,dwm创建它的ghost副本)。

namespace HungProcessName
{
    using System.Runtime.InteropServices;
    using System.Threading;
    using System.Diagnostics;
    using System;

    class Program
    {
        [DllImport("user32.dll")]
        private static extern IntPtr GetForegroundWindow();
        [DllImport("user32.dll")]
        private static extern IntPtr GhostWindowFromHungWindow(IntPtr hwnd);
        [DllImport("user32.dll")]
        private static extern IntPtr HungWindowFromGhostWindow(IntPtr hwnd);
        [DllImport("user32.dll")]
        private static extern bool IsHungAppWindow(IntPtr hwnd);
        [DllImport("user32.dll")]
        private static extern uint GetWindowThreadProcessId(IntPtr hwnd, out uint procId);

        static void Main(string[] args)
        {
            while (true)
            {
                var hwnd = GetForegroundWindow();
                Console.WriteLine("Foreground window: {0}", hwnd);
                if (IsHungAppWindow(hwnd))
                {
                    var hwndReal = HungWindowFromGhostWindow(hwnd);
                    uint procId = 0;
                    GetWindowThreadProcessId(hwndReal, out procId);
                    if (procId > 0)
                    {
                        Process proc = null;
                        try { proc = Process.GetProcessById((int)procId); }
                        catch (Exception ex)
                        {
                            Console.WriteLine("Could not get proces with Id '{0}': {1}", procId, ex);
                        }
                        if (proc != null)
                        {
                            Console.WriteLine("Ghost hwnd: {0}, Real hwnd: {1}. ProcessId: {2}, Proccess name: {3}",
                                hwnd, hwndReal, procId, proc.ProcessName);
                        }
                    }
                }
                Thread.Sleep(100);
            }
        }
    }
}

【讨论】:

  • 我们为什么要使用这个未记录的 api?你肯定明白其中的风险吗?你意识到你不应该这样做吗?谁说悬窗有鬼窗。很多时候他们没有。进程可以禁用重影。窗口也可以挂起并且不会出现重影,因为没有人尝试与之交互。
  • @David Heffernan,至少 TaskManager[taskmgr.exe] uses this technique。我给了测试代码。在检查之前可以发送带有 WM_NULL 的SendMessageTimeout。当然,如果有人打电话给DisableProcessWindowsGhosting,那就不行了。你有更好的主意吗?
  • 任务管理器是is shell的一部分。当然它可以使用私有 api 调用。但你不能。这个问题的问题是我们不知道你为什么要问。也许你真正的问题有不同的解决方案。
【解决方案2】:

使用 C#,System.DiagnosticsSystem.Linq 你可以这样做:

List<IntPtr> handles = System.Diagnostics.Process.GetProcesses()
                                                 .Where(x => !x.Responding)
                                                 .Select(x => x.MainWindowHandle).ToList();

返回未响应进程的句柄。

【讨论】:

  • 它将给出未响应应用程序的进程 ID。但是如何与前景窗口映射呢?
  • 我应该使用 Process.MainWindowHandle 吗?
  • @ArtavazdBalayan 进程必须有一个接口,MainWindowHandle 才能工作。
  • 起初我接受了您的回答,因为它确实会挂起应用程序。但是如果前台应用程序挂起,GetForegroundWindow 将返回幽灵窗口 HWND(由 DWM 创建),而不是真实窗口 HWND。您知道如何在不使用我的示例中的未记录函数的情况下将幽灵 HWND 转换为真正的 HWND 的任何其他想法吗?
猜你喜欢
  • 2010-11-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-05-25
  • 1970-01-01
相关资源
最近更新 更多