2010-03-28 68 views
24

如何找到使用c#的特定進程創建的所有窗口?如何使用.NET枚舉屬於特定進程的所有窗口?

UPDATE

我需要枚舉所有使用該應用程序的PID(進程ID)屬於一個特定過程的窗口。

+1

重複http://stackoverflow.com/questions/2281429/how-to-enumerate-all-windows-within-a-process – 2010-03-28 03:54:33

+0

@布賴恩的 - 不會鍵入從Process.MainWindowHandle和EnumChildWindows工作,而不是枚舉所有打開的窗口? – Gishu 2010-03-28 04:06:10

+0

@Gishu:不,但您可能可以使用Win32 API中的MainWindowHandle FindWindowEx – 2010-03-28 12:38:32

回答

11

使用Win32 API EnumWindows(如果您想要子窗口EnumChildWindows)),或者您也可以使用EnumThreadWindows

[DllImport("user32.dll", CharSet=CharSet.Auto, SetLastError=true)] 
public static extern bool EnumWindows(EnumThreadWindowsCallback callback, IntPtr extraData); 

然後檢查其處理每個窗口屬於通過使用Win32 API GetWindowThreadProcessId

[DllImport("user32.dll", CharSet=CharSet.Auto, SetLastError=true)] 
public static extern int GetWindowThreadProcessId(HandleRef handle, out int processId); 
+2

C#示例:http://www.pinvoke.net/default.aspx/user32/EnumWindows.html – shf301 2010-03-28 03:55:31

+0

嗯,這列舉了每個窗口線。它需要多一點工作才能找到每個進程的窗口。請參見[Konstantin的答案](http://stackoverflow.com/a/2584672/111575)。 – Abel 2012-04-01 23:46:44

+0

更好地使用康斯坦丁的答案! – 2013-10-03 11:14:04

64
delegate bool EnumThreadDelegate(IntPtr hWnd, IntPtr lParam); 

[DllImport("user32.dll")] 
static extern bool EnumThreadWindows(int dwThreadId, EnumThreadDelegate lpfn, 
    IntPtr lParam); 

static IEnumerable<IntPtr> EnumerateProcessWindowHandles(int processId) 
{ 
    var handles = new List<IntPtr>(); 

    foreach (ProcessThread thread in Process.GetProcessById(processId).Threads) 
     EnumThreadWindows(thread.Id, 
      (hWnd, lParam) => { handles.Add(hWnd); return true; }, IntPtr.Zero); 

    return handles; 
} 

和樣本用法:

private const uint WM_GETTEXT = 0x000D; 

[DllImport("user32.dll", CharSet = CharSet.Auto)] 
static extern IntPtr SendMessage(IntPtr hWnd, uint Msg, int wParam, 
    StringBuilder lParam); 

[STAThread] 
static void Main(string[] args) 
{ 
    foreach (var handle in EnumerateProcessWindowHandles(
     Process.GetProcessesByName("explorer").First().Id)) 
    { 
     StringBuilder message = new StringBuilder(1000); 
     SendMessage(handle, WM_GETTEXT, message.Capacity, message); 
     Console.WriteLine(message); 
    } 
} 
+1

感謝您發佈這一個!用這種方法(「掃描進程」 - >「掃描線程」 - >「掃描窗口」,而不是「掃描窗口」 - >「檢查進程ID」),我看到了更好的性能。 – Marcus 2014-04-26 06:29:16

3

古老的線程,但它讓我開始所以這裏有一個小實用函數,它會找到一個匹配lambda(Predicate)的子窗口。易於更改以返回列表。謂詞中處理了多個標準。

public delegate bool Win32Callback(IntPtr hwnd, IntPtr lParam); 

    [DllImport("user32.Dll")] 
    [return: MarshalAs(UnmanagedType.Bool)] 
    public static extern bool EnumChildWindows(IntPtr parentHandle, Win32Callback callback, IntPtr lParam); 

    /// <summary> 
    /// Find a child window that matches a set of conditions specified as a Predicate that receives hWnd.  Returns IntPtr.Zero 
    /// if the target window not found.  Typical search criteria would be some combination of window attributes such as 
    /// ClassName, Title, etc., all of which can be obtained using API functions you will find on pinvoke.net 
    /// </summary> 
    /// <remarks> 
    ///  <para>Example: Find a window with specific title (use Regex.IsMatch for more sophisticated search)</para> 
    ///  <code lang="C#"><![CDATA[var foundHandle = Win32.FindWindow(IntPtr.Zero, ptr => Win32.GetWindowText(ptr) == "Dashboard");]]></code> 
    /// </remarks> 
    /// <param name="parentHandle">Handle to window at the start of the chain.  Passing IntPtr.Zero gives you the top level 
    /// window for the current process.  To get windows for other processes, do something similar for the FindWindow 
    /// API.</param> 
    /// <param name="target">Predicate that takes an hWnd as an IntPtr parameter, and returns True if the window matches.  The 
    /// first match is returned, and no further windows are scanned.</param> 
    /// <returns> hWnd of the first found window, or IntPtr.Zero on failure </returns> 
    public static IntPtr FindWindow(IntPtr parentHandle, Predicate<IntPtr> target) { 
     var result = IntPtr.Zero; 
     if (parentHandle == IntPtr.Zero) 
      parentHandle = Process.GetCurrentProcess().MainWindowHandle; 
     EnumChildWindows(parentHandle, (hwnd, param) => { 
      if (target(hwnd)) { 
       result = hwnd; 
       return false; 
      } 
      return true; 
     }, IntPtr.Zero); 
     return result; 
    } 

var foundHandle = Win32.FindWindow(IntPtr.Zero, ptr => Win32.GetWindowText(ptr) == "Dashboard"); 
相關問題