Найдите окно с определенным текстом для Процесса

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

Я не испытываю никаких затруднений при нахождении процесса, с

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 говорят, это не проблема, если я мог бы получить подпись окна также),

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

Спасибо

9
задан Axarydax 27 April 2010 в 08:30
поделиться

2 ответа

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

Вам понадобятся следующие объявления 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;
}
21
ответ дан 4 December 2019 в 08:51
поделиться

Вместо того, чтобы перечислять процессы и находить окно, я бы перечислил окна (используя EnumWindows ) и нашел процесс (используя GetGuiThreadInfo ).

3
ответ дан 4 December 2019 в 08:51
поделиться