使用pinvoke从点开始获取表单句柄

时间:2015-11-30 17:24:39

标签: c# winapi pinvoke

我尝试使用p / invoke从一个点获取一个窗口句柄,其中window是一个表单,而不是任何子控件。我有一个简单的界面,用户输入X和Y,然后使用Find按钮调用win32并获取必要的信息。我的问题是窗口不一定是一种形式,它也可以是一种控制。见下面的截图 - 在(100,100)碰巧是记事本的文本区域" StackOverflow"写在里面。结果,Found窗口显示" StackOverflow"。

enter image description here

有什么办法可以将窗口类型限制为Form吗?预期的结果是" Untitled - Notepad"对于以下测试用例。或者,有没有办法让另一个应用程序的控件提供其表单的句柄?简而言之,我需要从(x,y)点获得表单的标题。按钮单击处理程序代码:

private void btn_Find_Click(object sender, EventArgs e)
{
  int xPoint = Convert.ToInt32(txt_WindowX.Text);
  int yPoint = Convert.ToInt32(txt_WindowY.Text);

  IntPtr hWnd = Win32.GetWindowHandleFromPoint(xPoint, yPoint);
  txt_FormTitle.Text = Win32.GetWindowTitle(hWnd);
}

Win32类的主要部分来自这个答案:

下面提供了完整的Win32类代码:

public class Win32
{
  /// <summary>
  /// 
  /// </summary>
  /// <param name="hwnd"></param>
  /// <remarks>https://stackoverflow.com/questions/4604023/unable-to-read-another-applications-caption</remarks>
  public static string GetWindowTitle(IntPtr hwnd)
  {
    if (hwnd == IntPtr.Zero)
      throw new ArgumentNullException("hwnd");
    int length = Win32.SendMessageGetTextLength(hwnd, WM_GETTEXTLENGTH, IntPtr.Zero, IntPtr.Zero);
    if (length > 0 && length < int.MaxValue)
    {
      length++; // room for EOS terminator
      StringBuilder sb = new StringBuilder(length);
      Win32.SendMessageGetText(hwnd, WM_GETTEXT, (IntPtr)sb.Capacity, sb);
      return sb.ToString();
    }
    return String.Empty;
  }

  public static IntPtr GetWindowHandleFromPoint(int x, int y)
  {
    var point = new Point(x, y);
    return Win32.WindowFromPoint(point);
  }

  const int WM_GETTEXT = 0x000D;
  const int WM_GETTEXTLENGTH = 0x000E;

  [DllImport("user32.dll")]
  private static extern IntPtr WindowFromPoint(Point p);

  [DllImport("User32.dll", EntryPoint = "SendMessage")]
  private static extern int SendMessageGetTextLength(IntPtr hWnd, int msg, IntPtr wParam, IntPtr lParam);
  [DllImport("User32.dll", EntryPoint = "SendMessage", CharSet = CharSet.Auto)]
  private static extern IntPtr SendMessageGetText(IntPtr hWnd, int msg, IntPtr wParam, [Out] StringBuilder lParam);
}

1 个答案:

答案 0 :(得分:1)

您需要找到顶级窗口。从supplier_default_product(region, supplier) 产生的窗口开始。然后反复调用GetWindowHandleFromPoint,直到找到没有父级的窗口。没有父级的窗口是您正在寻找的顶级窗口。