2010-03-28 57 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"); 
相关问题