Я пытаюсь найти, было ли окно с определенным открыто Процессом. Тот процесс порождает несколько окон, и я должен проверить их всех.
Я не испытываю никаких затруднений при нахождении процесса, с
foreach (Process p in Process.GetProcesses())
{
if (p.MainModule.FileName.ToLower().EndsWith("foo.exe"))
FindChildWindowWithText(p); //do work
проблема состоит в том, что сделать затем. Я не могу использовать Процесс MainWindowText
, потому что это изменяется с тем, какой бы ни окно активируется.
Затем я попытался использовать функцию Windows EnumChildWindows
и GetWindowText
, но я не уверен, передаю ли я корректный дескриптор EnumChildWindows. EnumChildWindows
работы как ожидалось, когда переданный MainWindowHandle, но конечно MainWindowHandle изменяется с активным окном. Таким образом, я передал Process.Handle
, но я получаю различные дескрипторы и различные результаты при переключении окон приложения. (Я понимаю, что дескрипторы возвратов EnumChildWindows к не только окна, но и средства управления в .NET говорят, это не проблема, если я мог бы получить подпись окна также),
Возможно, я делаю это неправильный путь, и мне нужен другой подход - снова, моя проблема так же проста как нахождение окна с текстом, который соответствует определенному регулярному выражению. Таким образом, мне, вероятно, была бы нужна функция, которая перечисляет все окна, которые видимы в панели задач или около этого.
Спасибо
Получив процесс, вы можете перечислить все окна в процессе и проверить, соответствует ли какое-либо из них искомому окну.
Вам понадобятся следующие объявления 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);
Ниже приведен пример пары функций, которые можно использовать для поиска окон в определенном процессе, из вашего вопроса я понял, что у вас есть процесс, проблема в перечислении окон.
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") на любое выражение, которое будет удовлетворять вашим критериям поиска окна, это может быть regex и т.д.
Здесь также представлена версия 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;
}
Вместо того, чтобы перечислять процессы и находить окно, я бы перечислил окна (используя EnumWindows ) и нашел процесс (используя GetGuiThreadInfo ).