У меня есть процесс, который контролирует окно, которое пользователь в настоящее время работает (GetForegroundWindow). Чтобы получить идентификатор процесса по HWND, я использую GetWindowThreadProcessId. Но, если приложение на переднем плане висит, я получу идентификатор процесса Desktop Window Manager - dwm.exe. Я могу определить, что приложение висит на IsHungAppWindow. Но как получить реальный идентификатор процесса переднего плана?Как получить идентификатор процесса не отвечающего приложения переднего плана?
ответ
Мы можем использовать недокументированные методы из user32.dll HungWindowFromGhostWindow, чтобы получить реальный дескриптор окна из дескриптора (если окна висят, dwm создает свою копию-призрак).
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? Вы высоко цените риски? Вы понимаете, что вы не должны это делать? И кто говорит, что у висячего окна есть окно-призрак. Часто они этого не делают. Процесс может отключить ореолы. Также окно может зависать и не быть призванным, потому что никто еще не пытался взаимодействовать с ним. –
@ Давид Хеффернан, по крайней мере TaskManager [taskmgr.exe] [использует эту технику] (http://i67.tinypic.com/34dkl6f.png). Я дал тестовый код. Перед проверкой можно отправить [SendMessageTimeout] (https://msdn.microsoft.com/en-us//library/windows/desktop/ms644952 (v = vs.85) .aspx) с WM_NULL. Конечно, если кто-то назвал [DisableProcessWindowsGhosting] (https://msdn.microsoft.com/en-us/library/ms648415 (v = vs.85) .aspx), это не сработает. У вас есть идея? –
Диспетчер задач - это часть оболочки. Конечно, он может использовать частные вызовы api. Вы не можете, хотя. Проблема в том, что мы не знаем, почему вы спрашиваете. Возможно, ваша настоящая проблема имеет другое решение. –
Ну с использованием C#, System.Diagnostics
и System.Linq
вы можете сделать это:
List<IntPtr> handles = System.Diagnostics.Process.GetProcesses()
.Where(x => !x.Responding)
.Select(x => x.MainWindowHandle).ToList();
который возвращает дескрипторы процессов, которые не реагируют.
Это даст идентификаторы процессов не отвечающих приложений. Но как сопоставить его с передним окном? –
Должен ли я использовать Process.MainWindowHandle? –
@ArtavazdBalayan ответ обновлен. – user3185569
ли с помощью 'System.Diagnostics.Process' Class вариант для вас? – user3185569
@ user3185569, в чем преимущество System.Diagnostics.Process в моей ситуации? –
Вы пытались отфильтровать файл dwm.exe? – Essigwurst