2010-04-27 6 views
9

J'essaie de trouver si une fenêtre avec spécifique a été ouverte par un processus. Ce processus engendre plusieurs fenêtres, et je dois les vérifier toutes.Rechercher une fenêtre avec un texte spécifique pour un processus

J'ai aucun mal à trouver le processus, avec

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

le problème est de savoir quoi faire. Je ne peux pas utiliser le processus 'MainWindowText, car il change avec n'importe quelle fenêtre est activée.

Puis j'ai essayé d'utiliser la fonction Windows EnumChildWindows et GetWindowText, mais je ne suis pas sûr si je passe une poignée correcte à EnumChildWindows. Le EnumChildWindows fonctionne comme prévu lorsqu'il est passé MainWindowHandle, mais bien sûr MainWindowHandle change avec la fenêtre active. J'ai donc passé Process.Handle, mais j'ai des poignées différentes et des résultats différents lors de la commutation des fenêtres de l'application. (Je comprends que EnumChildWindows retourne poignées pour non seulement fenêtres, mais contrôles en parler .net, c'est pas un problème si je pouvais obtenir la légende de la fenêtre trop)

Peut-être que je fais cela dans le mauvais sens et J'ai besoin d'une approche différente - encore une fois, mon problème est aussi simple que de trouver une fenêtre avec du texte qui correspond à une expression régulière spécifique. Donc, je aurais probablement besoin d'une fonction qui énumère toutes les fenêtres, qui sont visibles dans la barre des tâches ou plus.

Merci

Répondre

19

Une fois que vous avez le processus, vous pouvez énumérer toutes les fenêtres dans le processus et le test le cas échéant d'entre eux correspondent à la fenêtre que vous recherchez.

Vous aurez besoin des déclarations P/Invoke suivant

[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); 

Le followng est un exemple d'une paire de fonctions qui peuvent être utilisées pour trouver les fenêtres dans un processus spécifique, je compris de votre question que vous avoir le processus, le problème est l'énumération des fenêtres.

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

Ensuite, vous pouvez appeler la fonction FindWindowInProcess pour trouver une fenêtre qui se termine par son titre « ABC » comme exemple.

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

Bien sûr, vous pouvez remplacer s => s.EndsWith (« ABC ») avec toute expression qui satisfera vos critères de recherche pour la fenêtre, il pourrait être une expression régulière, etc.

Voici aussi une version de FindThreadWindow qui vérifie également le premier niveau des fenêtres enfants. Vous pourriez aller plus loin et en faire une fonction récursive si vos fenêtres sont plus bas dans la hiérarchie.

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

réponse très élaborée, fonctionne comme un charme. – Axarydax

+0

Dans FindChildWindow ... ne devrait-il pas être hChildWnd au lieu de hWnd après avoir vérifié le résultat de compareTitle? – seveves

3

Au lieu de trouver et l'énumération des processus de la fenêtre, j'énumèrent les fenêtres (en utilisant EnumWindows) et trouve le processus (en utilisant GetGuiThreadInfo).

+0

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

Questions connexes