2010-04-27 14 views
9

Sto cercando di scoprire se una finestra con specifica è stata aperta da un processo. Quel processo genera più finestre, e ho bisogno di controllarle tutte.Trova finestra con testo specifico per un processo

ho avere problemi a trovare il processo, con

foreach (Process p in Process.GetProcesses()) 
{ 
    if (p.MainModule.FileName.ToLower().EndsWith("foo.exe")) 
    FindChildWindowWithText(p); //do work 

il problema è cosa fare dopo. Non posso usare Process 'MainWindowText, perché cambia con qualsiasi finestra attivata.

Quindi ho provato a utilizzare la funzione di Windows EnumChildWindows e GetWindowText, ma non sono sicuro se sto passando un handle corretto a EnumChildWindows. EnumChildWindows funziona come previsto quando viene passato MainWindowHandle, ma ovviamente MainWindowHandle cambia con la finestra attiva. Così ho passato Process.Handle, ma ottengo maniglie diverse e risultati diversi quando cambio le finestre dell'app. (Capisco che EnumChildWindows torna maniglie per non solo finestre, ma controlli in .net parlare, che non è un problema se potessi ottenere la didascalia della finestra di troppo)

Forse sto facendo nel modo sbagliato e Ho bisogno di un approccio diverso - di nuovo, il mio problema è semplice come trovare una finestra con testo che corrisponda a un'espressione regolare specifica. Quindi probabilmente avrei bisogno di una funzione che enumeri tutte le finestre, che sono visibili nella barra delle applicazioni o giù di lì.

Grazie

risposta

19

Una volta ottenuto il processo, è possibile enumerare tutte le finestre del processo e verificare se qualsiasi di loro corrispondono alla finestra che stai cercando.

avrete bisogno dei seguenti P/Invoke dichiarazioni

[DllImport("user32", SetLastError=true)] 
[return: MarshalAs(UnmanagedType.Bool)] 
private extern static bool EnumThreadWindows(int threadId, EnumWindowsProc callback, IntPtr lParam); 

[DllImport("user32", SetLastError = true)] 
[return: MarshalAs(UnmanagedType.Bool)] 
static extern bool EnumChildWindows(IntPtr hwndParent, EnumWindowsProc lpEnumFunc, IntPtr lParam); 

[DllImport("user32", SetLastError = true, CharSet = CharSet.Auto)] 
private extern static int GetWindowText(IntPtr hWnd, StringBuilder text, int maxCount); 

Il followng è un esempio di un paio di funzioni che possono essere utilizzati per trovare le finestre di uno specifico procedimento, ho capito dalla tua domanda che si avere il processo, il problema è enumerare le finestre.

public static IntPtr FindWindowInProcess(Process process, Func<string, bool> compareTitle) 
{ 
    IntPtr windowHandle = IntPtr.Zero; 

    foreach (ProcessThread t in process.Threads) 
    { 
    windowHandle = FindWindowInThread(t.Id, compareTitle); 
    if (windowHandle != IntPtr.Zero) 
    { 
     break; 
    } 
    } 

    return windowHandle; 
} 

private static IntPtr FindWindowInThread(int threadId, Func<string, bool> compareTitle) 
{ 
    IntPtr windowHandle = IntPtr.Zero; 
    EnumThreadWindows(threadId, (hWnd, lParam) => 
    { 
    StringBuilder text = new StringBuilder(200); 
    GetWindowText(hWnd, text, 200); 
    if (compareTitle(text.ToString())) 
    { 
     windowHandle = hWnd; 
     return false; 
    } 
    return true; 
    }, IntPtr.Zero); 

    return windowHandle; 
} 

Quindi è possibile chiamare la funzione FindWindowInProcess di trovare una finestra che è il titolo termina con "ABC" come esempio.

IntPtr hWnd = FindWindowInProcess(p, s => s.EndsWith("ABC")); 
if (hWnd != IntPtr.Zero) 
{ 
    // The window was found.... 
} 

Naturalmente è possibile sostituire s => s.EndsWith ("ABC") con qualsiasi espressione in grado di soddisfare i criteri di ricerca per la finestra, potrebbe essere un espressione regolare ecc

qui è anche una versione di FindThreadWindow che controlla anche il primo livello di finestre figlio. Potresti fare questo e renderlo una funzione ricorsiva se la tua finestra è più in basso nella gerarchia.

private static IntPtr FindWindowInThread(int threadId, Func<string, bool> compareTitle) 
{ 
    IntPtr windowHandle = IntPtr.Zero; 
    EnumThreadWindows(threadId, (hWnd, lParam) => 
    { 
    StringBuilder text = new StringBuilder(200); 
    GetWindowText(hWnd, text, 200);   
    if (compareTitle(text.ToString())) 
    { 
     windowHandle = hWnd; 
     return false; 
    } 
    else 
    { 
     windowHandle = FindChildWindow(hWnd, compareTitle); 
     if (windowHandle != IntPtr.Zero) 
     { 
     return false; 
     } 
    } 
    return true; 
    }, IntPtr.Zero); 

    return windowHandle; 
} 

private static IntPtr FindChildWindow(IntPtr hWnd, Func<string, bool> compareTitle) 
{ 
    IntPtr windowHandle = IntPtr.Zero; 
    EnumChildWindows(hWnd, (hChildWnd, lParam) => 
    { 
    StringBuilder text = new StringBuilder(200); 
    GetWindowText(hChildWnd, text, 200);   
    if (compareTitle(text.ToString())) 
    { 
     windowHandle = hChildWnd; 
     return false; 
    } 
    return true; 
    }, IntPtr.Zero); 

    return windowHandle; 
} 
+0

risposta molto elaborata, funziona come un fascino. – Axarydax

+0

In FindChildWindow ... non dovrebbe essere hChildWnd invece di hWnd dopo aver controllato il risultato di compareTitle? – seveves

3

Invece di enumerare i processi e trovare la finestra, mi piacerebbe enumerare le finestre (utilizzando EnumWindows) e trovare il processo (usando GetGuiThreadInfo).

+0

Oppure GetWindowsThreadProcessId (http://msdn.microsoft.com/en-us/library/ms633522(VS.85).aspx). –

Problemi correlati