【问题标题】:Enable user to select control/window from another process使用户能够从另一个进程中选择控件/窗口
【发布时间】:2013-11-16 17:09:00
【问题描述】:

如何使用户能够从任何窗口中选择控件?像 inspect.exe 或 WinySpy++ 这样的东西可以做(见截图)。

编辑: 通过“选择一个控件”,我的意思是如何在鼠标指针下获得控件的句柄,以便我可以用它做一些事情(例如,在它周围绘制框,获取它的位置和名称)。我知道我需要使用 WinAPI,只是不知道从哪里开始(如何获取鼠标指针下的控件句柄)。

【问题讨论】:

  • “选择一个控件”是什么意思?把重点放在它上面?调用它的关联命令?完全是别的东西吗?
  • 它检查操作系统消息。您必须为此检查 Windows API。
  • 我已经更新了这个问题,很抱歉没有从一开始就更好地解释它。
  • GetCursorPos, WindowFromPoint.
  • 创建一个无边框的最大化表单,将其 BackgroundImage 属性设置为您使用 Graphics.CopyFromScreen() 制作的屏幕截图。使用 Paint 事件绘制矩形。您需要的基本代码在this answer

标签: c# .net winforms winapi


【解决方案1】:

从这里开始:(这非常粗略,需要更多的工作!)

  1. 在空白表单中,添加一个 PictureBox 和四个标签。
  2. 将 PictureBox 的 BorderStyle 更改为 FixedSingle。
  3. 在顶部添加using System.Runtime.InteropServices; 与其他 using 语句一起编写代码。
  4. 连接鼠标的 MouseDown()、MouseMove 和 MouseUp() 事件 PictureBox 到下面的相应方法。
  5. 运行它并在屏幕上拖动 PictureBox...

代码:

public partial class Form1 : Form
{

    [StructLayout(LayoutKind.Sequential)]
    public struct RECT
    {
        public int Left;
        public int Top;
        public int Right;
        public int Bottom;
    }

    public const int WM_GETTEXT = 0xD;
    public const int WM_GETTEXTLENGTH = 0x000E;

    [DllImport("user32.dll")]
    public static extern IntPtr WindowFromPoint(Point point);

    [DllImport("user32.dll", CharSet = CharSet.Auto)]
    public static extern int GetClassName(IntPtr handle, StringBuilder ClassName, int MaxCount);

    [DllImport("user32.dll")]
    public static extern int SendMessage(IntPtr handle, int msg, int Param1, int Param2);

    [DllImport("user32.dll")]
    public static extern int SendMessage(IntPtr handle, int msg, int Param, System.Text.StringBuilder text);

    [DllImport("user32.dll")]
    [return: MarshalAs(UnmanagedType.Bool)]
    public static extern bool GetWindowRect(IntPtr handle, out RECT Rect);

    public class WindowInfo
    {
        public IntPtr Handle;
        public string ClassName;
        public string Text;
        public Rectangle Rect;

        public WindowInfo(IntPtr Handle)
        {
            this.Handle = Handle;
            this.ClassName = GetWindowClassName(Handle);
            this.Text = GetWindowText(Handle);
            this.Rect = GetWindowRectangle(Handle);
        }
    }

    WindowInfo LastWindow = null;
    WindowInfo CurWindow;

    public Form1()
    {
        InitializeComponent();
    }

    private void pictureBox1_MouseDown(object sender, MouseEventArgs e)
    {
        if (e.Button == System.Windows.Forms.MouseButtons.Left)
        {
            pictureBox1.Cursor = Cursors.Cross;
        }
    }

    private void pictureBox1_MouseMove(object sender, MouseEventArgs e)
    {
        if (e.Button == System.Windows.Forms.MouseButtons.Left)
        {
            Point pt = Cursor.Position;
            this.Text = "Mouse Position: " + pt.ToString();
            this.CurWindow = new WindowInfo(WindowFromPoint(pt));

            label1.Text = "Handle: " + this.CurWindow.Handle.ToString("X");
            label2.Text = "Class: " + this.CurWindow.ClassName;
            label3.Text = "Text: " + this.CurWindow.Text;
            label4.Text = "Rectangle: " + this.CurWindow.Rect.ToString();

            if (this.LastWindow == null)
            {
                ControlPaint.DrawReversibleFrame(this.CurWindow.Rect, Color.Black, FrameStyle.Thick);
            }
            else if (!this.CurWindow.Handle.Equals(this.LastWindow.Handle))
            {
                ControlPaint.DrawReversibleFrame(this.LastWindow.Rect, Color.Black, FrameStyle.Thick);
                ControlPaint.DrawReversibleFrame(this.CurWindow.Rect, Color.Black, FrameStyle.Thick);                   
            }

            this.LastWindow = this.CurWindow;
        }
    }

    private void pictureBox1_MouseUp(object sender, MouseEventArgs e)
    {
        if (e.Button == System.Windows.Forms.MouseButtons.Left)
        {
            pictureBox1.Cursor = Cursors.Default;
            if (this.LastWindow != null)
            {
                ControlPaint.DrawReversibleFrame(this.LastWindow.Rect, Color.Black, FrameStyle.Thick);

                // ... do something with "this.LastWindow" ...

            }
        }
    }

    public static string GetWindowClassName(IntPtr handle)
    {
        StringBuilder buffer = new StringBuilder(128);
        GetClassName(handle, buffer, buffer.Capacity);
        return buffer.ToString();
    }

    public static string GetWindowText(IntPtr handle)
    {
        StringBuilder buffer = new StringBuilder(SendMessage(handle, WM_GETTEXTLENGTH,0,0) + 1);
        SendMessage(handle, WM_GETTEXT, buffer.Capacity, buffer);
        return buffer.ToString();
    }

    public static Rectangle GetWindowRectangle(IntPtr handle)
    {
        RECT rect = new RECT();
        GetWindowRect(handle, out rect);
        return new Rectangle(rect.Left, rect.Top, (rect.Right - rect.Left) + 1, (rect.Bottom - rect.Top) + 1);
    }

}

【讨论】:

  • 谢谢。拯救了我的一天
【解决方案2】:

使用GetCursorPos函数获取当前光标位置。

使用WindowFromPoint获取包含指定点的窗口。

至于画矩形,看source code of WinSpy++

【讨论】:

  • 其他有用的 API 调用:GetWindowText、GetClassName、GetWindowLongA、GetWindowRect ...查看 pinvoke.net 的声明。
猜你喜欢
  • 2021-11-12
  • 1970-01-01
  • 2019-05-27
  • 2021-05-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多