windows 查找带有进程特定文本的窗口

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/2719756/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-15 14:21:20  来源:igfitidea点击:

Find window with specific text for a Process

c#.netwindowsprocesspinvoke

提问by Axarydax

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.

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

Then I've tried to use Windows function EnumChildWindowsand GetWindowText, but I am not sure if I'm passing a correct handle to EnumChildWindows. The EnumChildWindowsworks 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 controlsin .net speak, that's no problem if I could get the caption of the window too)

然后我尝试使用 Windows 函数EnumChildWindowsGetWindowText,但我不确定我是否将正确的句柄传递给 EnumChildWindows。在EnumChildWindows通过MainWindowHandle的时候,但当然MainWindowHandle与活动窗口的变化按预期工作。所以我通过了Process.Handle,但是在切换应用程序的窗口时我得到了不同的句柄和不同的结果。(据我所知,EnumChildWindows返回的句柄,不仅窗户,但控制在.NET讲,这是没有问题的,如果我能得到窗口的标题太)

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

谢谢

回答by Chris Taylor

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

您将需要以下 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);

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.

然后,您可以调用 FindWindowInProcess 函数来查找标题以“ABC”结尾的窗口作为示例。

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.

当然,您可以将 s => s.EndsWith("ABC") 替换为满足窗口搜索条件的任何表达式,它可以是正则表达式等。

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.

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

回答by Eric Brown

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

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