2010-03-28 7 views
24

¿Cómo puedo encontrar todas las ventanas creadas por un proceso particular usando C#?¿Cómo enumerar todas las ventanas que pertenecen a un proceso particular usando .NET?

ACTUALIZACIÓN

necesito enumerar todas las ventanas que pertenecen a un proceso particular usando la (ID de proceso) PID de la una aplicación.

+1

duplicado de http://stackoverflow.com/questions/2281429/how-to-enumerate-all-windows-within-a-process –

+0

@ Brian - no lo haría Desbloquear desde Process.MainWindowHandle y EnumChildWindows funciona en lugar de enumerar todas las ventanas abiertas? – Gishu

+0

@Gishu: No, pero puede ser capaz de utilizar MainWindowHandle dentro de la API de Win32 FindWindowEx –

Respuesta

11

utilizar la API de Win32 EnumWindows (si quieres ventanas secundarias EnumChildWindows)), o, alternativamente, se puede usar EnumThreadWindows.

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

continuación, compruebe qué proceso pertenece cada ventana para mediante el uso de la API de Win32 GetWindowThreadProcessId

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

C# ejemplo: http://www.pinvoke.net/default.aspx/user32/EnumWindows.html – shf301

+0

Hmm, esto enumera las ventanas por hilo. Requiere un poco más de trabajo para encontrar las ventanas por proceso. Ver [la respuesta de Konstantin a continuación] (http://stackoverflow.com/a/2584672/111575). – Abel

+0

¡Mejor uso de la respuesta de Konstantin! –

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; 
} 

y ejemplos de uso:

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

Gracias por publicar este! Veo mucho mejor rendimiento con este enfoque ("escanear procesos" -> "escanear hilos" -> "escanear ventanas" en lugar de "escanear ventanas" -> "verificar identificación del proceso") – Marcus

3

hilo antiguo, pero me empezó así que aquí hay una pequeña función de utilidad que encontrará una ventana secundaria que coincide con una lambda (predicado). Sé fácil de cambiar para devolver una lista. Múltiples criterios se manejan en el predicado.

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; 
    } 

Ejemplo

var foundHandle = Win32.FindWindow(IntPtr.Zero, ptr => Win32.GetWindowText(ptr) == "Dashboard"); 
Cuestiones relacionadas