2010-04-27 9 views
9

Estoy tratando de encontrar si una ventana con específico ha sido abierta por un proceso. Ese proceso genera múltiples ventanas, y necesito revisarlas todas.Buscar ventana con texto específico para un proceso

no tengo problemas para encontrar el proceso, con

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

el problema es qué hacer a continuación. No puedo usar el Proceso 'MainWindowText, porque cambia con la ventana que esté activada.

Luego he intentado usar la función de Windows EnumChildWindows y GetWindowText, pero no estoy seguro de si estoy pasando un identificador correcto a EnumChildWindows. El EnumChildWindows funciona como se esperaba al pasar MainWindowHandle, pero, por supuesto, MainWindowHandle cambia con la ventana activa. Así que pasé Process.Handle, pero obtengo diferentes identificadores y resultados diferentes al cambiar las ventanas de la aplicación. (Entiendo que EnumChildWindows vuelve asas para no sólo ventanas, pero controles en hablar .net, eso no es problema si podía conseguir el título de la ventana también)

Tal vez estoy haciendo esto por el camino equivocado y Necesito un enfoque diferente. De nuevo, mi problema es tan simple como encontrar una ventana con texto que coincida con una expresión regular específica. Así que probablemente necesitaría una función que enumera todas las ventanas, que son visibles en la barra de tareas o más.

Gracias

Respuesta

19

vez que tenga el proceso, se puede enumerar todas las ventanas en el proceso y prueba si los hay de ellos coinciden con la ventana que está buscando.

Necesitará los siguientes P/Invoke declaraciones

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

El followng es un ejemplo de un par de funciones que se pueden utilizar para encontrar las ventanas de un proceso específico, comprendí por su pregunta que usted tener el Proceso, el problema es enumerar las ventanas.

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

A continuación, puede llamar a la función FindWindowInProcess para encontrar una ventana que es el título termina con "ABC" como ejemplo.

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

Por supuesto se puede reemplazar s => s.EndsWith ("ABC") con cualquier expresión que satisfaga sus criterios de búsqueda de la ventana, que podría ser una expresión regular, etc.

Aquí es también una versión de FindThreadWindow que también verificará el primer nivel de ventanas secundarias. Puede llevar esto más allá y convertirlo en una función recursiva si sus ventanas están más abajo en la jerarquía.

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

respuesta muy elaborada, funciona como un encanto. – Axarydax

+0

En FindChildWindow ... ¿no debería ser hChildWnd en lugar de hWnd después de comprobar el resultado de compareTitle? – seveves

3

En lugar de enumerar los procesos y la búsqueda de la ventana, me gustaría enumerar las ventanas (utilizando EnumWindows) y encontrar el proceso (utilizando GetGuiThreadInfo).

+0

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

Cuestiones relacionadas