2010-03-28 11 views
24

Come posso trovare tutte le finestre create da un particolare processo usando C#?Come enumerare tutte le finestre appartenenti a un particolare processo utilizzando .NET?

UPDATE

devo enumerare tutte le finestre che appartengono ad un processo particolare utilizzando le PID (ID di processo) del un'applicazione.

+1

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

+0

@ Brian - no la chiusura di Process.MainWindowHandle e EnumChildWindows funziona invece di enumerare tutte le finestre aperte? – Gishu

+0

@Gishu: No, ma potresti essere in grado di utilizzare MainWindowHandle all'interno dell'API Win32 FindWindowEx –

risposta

11

Utilizzare l'API Win32 EnumWindows (se si desidera windows figlio EnumChildWindows), o in alternativa è possibile utilizzare EnumThreadWindows.

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

Poi verificare quali elaborare ogni finestra appartiene utilizzando l'API Win32 GetWindowThreadProcessId

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

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

+0

Hmm, questo enumera le finestre per filo. Richiede un po 'più di lavoro per trovare le finestre per processo. Vedi [risposta di Konstantin qui sotto] (http://stackoverflow.com/a/2584672/111575). – Abel

+0

Meglio usare la risposta di 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; 
} 

e l'uso del campione:

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

Grazie per aver postato questo! Sto osservando le migliori prestazioni con questo approccio ("scan processes" -> "scan threads" -> "scan windows" invece di "scan windows" -> "check process id") – Marcus

3

Antica filo, ma mi è cominciato quindi ecco una piccola funzione di utilità che troverà una finestra figlio che corrisponde a una lambda (Predicato). Essere facile da cambiare per restituire una lista. Più criteri sono gestiti nel predicato.

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

Esempio

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