Find window with specific text for a Process

I'm trying to find if a window with specific has been open by a Process. That process spawns multiple windows, and I need to check them all.

I have no trouble finding the process, with

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

the problem is what to do next. I cannot use Process' MainWindowText , because it changes with whichever window is activated.

Then I've tried to use Windows function EnumChildWindows and GetWindowText , but I am not sure if I'm passing a correct handle to EnumChildWindows. The EnumChildWindows works as expected when passed MainWindowHandle, but of course the MainWindowHandle changes with active window. So I passed Process.Handle , but I get different handles and different results when switching the app's windows. (I understand that EnumChildWindows returns handles to not only windows, but controls in .net speak, that's no problem if I could get the caption of the window too)

Maybe I am doing this the wrong way and I need a different approach - again, my problem is as simple as finding a window with text that matches specific regular expression. So I would probably need a function that enumerates all windows, that are visible in the taskbar or so.

Thanks


Once you have the Process, you can enumerate all the Windows in the process and test if any of them match the window you are looking for.

You will need the following P/Invoke declarations

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

The followng is an example of a pair of functions that can be used to find the windows in a specific process, I understood from your question that you have the Process, the problem is enumerating the windows.

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

Then you can call the FindWindowInProcess function to find a window that's title ends with "ABC" as an example.

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

Of course you can replace s => s.EndsWith("ABC") with any expression that will satisfy your search criteria for the window, it could be a regex etc.

Here is also a version of FindThreadWindow that will also check the first level of child windows. You could take this further and make it a recursive function if your windows is deeper down in the hierarchy.

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)。


几乎相似的(或者是完全一样的?)的问题,并接受的答案,你可以参考一下:.NET(C#):获取子窗口时,你只有一个进程句柄或PID?

链接地址: http://www.djcxy.com/p/38836.html

上一篇: 在Mac上查找(并终止)进程锁定端口3000

下一篇: 查找包含特定文本的窗口