2010-04-27 2 views
9

Я пытаюсь найти, если окно с определенным было открыто процессом. Этот процесс порождает несколько окон, и мне нужно их проверить.Найти окно с конкретным текстом для процесса

У меня нет проблем с поиском процесса, с

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

проблемой является то, что делать дальше. Я не могу использовать Process 'MainWindowText, потому что он изменяется в зависимости от того, какое окно активировано.

Затем я попытался использовать функцию Windows EnumChildWindows и GetWindowText, но я не уверен, передаю ли я правильный дескриптор EnumChildWindows. EnumChildWindows работает, как и ожидалось, при передаче MainWindowHandle, но, конечно, MainWindowHandle изменяется с активным окном. Поэтому я прошел Process.Handle, но при переключении окон приложения я получаю разные ручки и разные результаты. (Я понимаю, что EnumChildWindows возвращает дескрипторы не только окна, но управления в .net говорит, что нет никаких проблем, если я мог бы получить заголовок окна тоже)

Может быть, я делаю это неправильным путь и Мне нужен другой подход - опять же, моя проблема так же проста, как найти окно с текстом, которое соответствует определенному регулярному выражению. Поэтому мне, вероятно, понадобится функция, которая перечисляет все окна, которые видны на панели задач или около того.

Благодаря

ответ

19

После того, как у вас есть процесс, вы можете все перечислить Windows, в процессе и тестирования, если какой-либо из них соответствуют интересующему вас окну.

Вам понадобится следующее P/Invoke деклараций

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

followng является примером пары функций, которые могут быть использованы, чтобы найти окно в определенном процессе, я понял из вашего вопроса, что вам есть процесс, проблема заключается в перечислении окон.

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

Тогда вы можете вызвать функцию FindWindowInProcess найти окно, которое название заканчивается «ABC» в качестве примера.

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

Конечно, вы можете заменить s => s.EndsWith («ABC») с любым выражением, которое будет удовлетворять ваши критерии поиска для окна, это может быть регулярным выражением и т.д.

Здесь также версию FindThreadWindow, которая также проверит первый уровень дочерних окон. Вы можете сделать это дальше и сделать его рекурсивной функцией, если ваши окна будут глубже в иерархии.

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

очень сложный ответ, работает как шарм. – Axarydax

+0

В FindChildWindow ... не должно быть hChildWnd вместо hWnd после проверки результата compareTitle? – seveves

3

Вместо перечисления процессов и найти окно, я бы перечислить окна (с помощью EnumWindows) и найти способ (с использованием GetGuiThreadInfo).

+0

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

Смежные вопросы