查找包含进程特定文本的窗口

发布于 2024-08-30 13:52:25 字数 799 浏览 1 评论 0原文

我正在尝试查找某个进程是否已打开特定的窗口。该过程会产生多个窗口,我需要检查所有窗口。

我很容易找到流程,

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 中的 controls,如果我也能获取窗口的标题,那就没问题了)

也许我是以错误的方式执行此操作,我需要一种不同的方法 - 同样,我的问题就像找到一个包含与特定正则表达式匹配的文本的窗口一样简单。所以我可能需要一个函数来枚举在任务栏等中可见的所有窗口。

谢谢

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

通知家属抬走 2024-09-06 13:52:25

拥有进程后,您可以枚举进程中的所有窗口并测试其中是否有任何窗口与您要查找的窗口匹配。

您将需要以下 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") 与任何满足窗口搜索条件的表达式,它可以是正则表达式等。

这也是 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;
}

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;
}
挥剑断情 2024-09-06 13:52:25

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

Rather than enumerating processes and finding the window, I'd enumerate the windows (using EnumWindows) and find the process (using GetGuiThreadInfo).

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文