查找具有Process的特定文本的窗口

时间:2010-04-27 08:30:34

标签: c# .net windows process pinvoke

我正在尝试查找具有特定功能的窗口是否已由进程打开。这个过程产生了多个窗口,我需要检查它们。

我可以通过

找到这个过程
foreach (Process p in Process.GetProcesses())
{
  if (p.MainModule.FileName.ToLower().EndsWith("foo.exe"))
     FindChildWindowWithText(p); //do work

问题是接下来要做什么。我不能使用Process'MainWindowText,因为它会随着激活的窗口而改变。

然后我尝试使用Windows函数EnumChildWindowsGetWindowText,但我不确定我是否将正确的句柄传递给EnumChildWindows。传递MainWindowHandle时,EnumChildWindows按预期工作,但MainWindowHandle当然会随活动窗口而变化。所以我通过了Process.Handle,但在切换应用程序的窗口时,我得到了不同的句柄和不同的结果。 (我知道EnumChildWindows不仅会向 windows 返回句柄,而且.net中的控件会说话,如果我也能得到窗口的标题就没问题了)

也许我这样做是错误的,我需要一种不同的方法 - 再次,我的问题就像找到一个文本与特定正则表达式相匹配的窗口一样简单。所以我可能需要一个枚举所有窗口的函数,这些窗口在任务栏中都是可见的。

由于

3 个答案:

答案 0 :(得分:20)

完成流程后,您可以枚举流程中的所有Windows,并测试其中是否有任何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);

以下是一对可用于在特定过程中查找窗口的函数示例,我从您的问题中了解到您有过程,问题是枚举窗口。

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 =&gt; 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;
}

答案 1 :(得分:3)

我不是枚举进程并找到窗口,而是枚举窗口(使用EnumWindows)并找到进程(使用GetGuiThreadInfo)。

答案 2 :(得分:0)

与您接受的答案几乎相似(或完全相同?)的问题,您可以参考:.NET (C#): Getting child windows when you only have a process handle or PID?