2016-07-28 30 views
-1

我有一個進程監視用戶當前正在工作的窗口(GetForegroundWindow)。要獲得HWND的進程ID,我使用GetWindowThreadProcessId。但是,如果前臺應用程序被掛起,我會得到Desktop Window Manager - dwm.exe的進程ID。我可以確定是由IsHungAppWindow掛起的應用程序。 但如何獲得前臺掛起應用程序的真實進程ID?如何獲得沒有響應的前臺應用程序的進程ID?

+0

使用'System.Diagnostics.Process'類適合您的選項? – user3185569

+0

@ user3185569,在我的情況下,System.Diagnostics.Process有什麼好處? –

+0

您試圖過濾掉dwm.exe? – Essigwurst

回答

0

我們可以使用user32.dll中的未記錄方法HungWindowFromGhostWindow從鬼句柄(如果窗口掛起,dwm創建它的副本)獲取真實的窗口句柄。 Undocumented functions: HungWindowFromGhostWindow and GhostWindowFromHungWindow

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); 
      } 
     } 
    } 
} 
+0

我們爲什麼要使用這個無證API?你肯定會欣賞風險嗎?你意識到你不應該這樣做?誰說懸掛的窗戶有一扇幽靈窗戶。他們通常不會。進程可以禁用重影。此外窗口可以掛起,不會被幻影,因爲沒有人試圖與它進行交互。 –

+1

@David Heffernan,至少TaskManager [taskmgr.exe] [使用此技術](http://i67.tinypic.com/34dkl6f.png)。我給了測試代碼。在檢查之前,可以使用WM_NULL發送[SendMessageTimeout](https://msdn.microsoft.com/en-us//library/windows/desktop/ms644952(v = vs.85).aspx)。當然,如果有人調用[DisableProcessWindowsGhosting](https://msdn.microsoft.com/en-us/library/ms648415(v = vs.85).aspx),它將無法工作。你有更好的主意嗎? –

+0

好的任務管理器是is shell的一部分。當然,它可以使用私人API調用。你不能。這個問題的問題是我們不知道你爲什麼問。也許你真正的問題有不同的解決方案。 –

1

那麼使用C#,System.DiagnosticsSystem.Linq你可以這樣做:

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

它返回一個不響應的進程的句柄。

+0

它會給出沒有響應應用程序的進程ID。但如何將它與前景窗口進行映射? –

+0

我應該使用Process.MainWindowHandle嗎? –

+0

@ArtavazdBalayan答案已更新。 – user3185569