c#获取句柄,并对第三方软件的输入框和按钮进行控制 您所在的位置:网站首页 获取当前窗口句柄的函数 c#获取句柄,并对第三方软件的输入框和按钮进行控制

c#获取句柄,并对第三方软件的输入框和按钮进行控制

#c#获取句柄,并对第三方软件的输入框和按钮进行控制| 来源: 网络整理| 查看: 265

刚学了没多久,还有很多地方没有理解到位,还请大家指正。

当程序运行起来,就会显示在任务管理器中,软件中的每个事件,比如按钮,文本框等一些控件,每个事件都会产生一个句柄,句柄就是这些事件的标识符。如果拿到句柄就可以自己写软件对第三方软件进行控制。同一个软件在不同的电脑中的句柄一般是不一样的,但是获取的过程都是一样的。只要在当前电脑上找到事件的标识符即可。

具体的窗口句柄的结构可以用微软的spy++查看,spy++可以在VS的工具里找到,也可以到安装目录下找到。

 

 

拖动这个标记到需要查看的控件上松开,即可显示当前事件的句柄,点击确定搜索,即可确定当前控件所在的窗口位置。

有时候软件打开了但是搜索失败,需要对spy++刷新,只要电脑进程变了,句柄列表没来得及更新,这时候就需要对spy++进行刷新。

有的软件不能获取具体控件的句柄,比如像微信、QQ这样的,只能获取一个顶层的窗口。像这样的,那就说明这种程序的控件其实是不存在的,是画出来的,这种程序叫做directui程序,只能模仿鼠标键盘操作。

不是说所有的窗口都支持spy++来抓取,一般是windows标准窗口才能获取控件句柄,以及发送消息等。

接下来就是寻找句柄:

我用的是VS2022,他可以根据自己写的代码自动添加using,不用人为的添加,所以在这里就省略using。

[DllImport("User32.dll", EntryPoint = "FindWindow")] private static extern IntPtr FindWindow(string lpClassName, string lpWindowName); [DllImport("User32.dll", EntryPoint = "FindWindowEx")] private static extern IntPtr FindWindowEx(IntPtr hwndParent, IntPtr hwndChildAfter, string lpClassName, string lpWindowName); [DllImport("User32.dll", EntryPoint = "SendMessage")] private static extern int SendMessage(IntPtr hWnd, int Msg, IntPtr wParam, string lParam);

这里声明了三个方法。

第一个是FindWindow,这个方法只能查找顶层窗口的句柄,不能查找子窗口。

第二个是FindWindowEx,这个方法是用来查找子窗口的。

第三个是SendMessage,这个方法可以向指定的文本框输入数据和字符,还可以点击按钮。

我是要获取Pronterface那个软件的句柄,具体控件为右下角文本框和Send按钮。

这个软件有很多层,而且都是Windows标准控件。

private void button1_Click(object sender, EventArgs e) { IntPtr hwnd = FindWindow("wxWindowClassNR", "Pronterface"); //FindWindow只查找顶层窗口 IntPtr htextbox = FindWindowEx(hwnd, IntPtr.Zero, "wxWindowClassNR", null);//(当前为第一层)IntPtr.Zero则表示获得第一个子窗口。第三个参数表示你需要找的子窗口的类型,第四个参数一般为null。 //如果一个窗口中有两个文本框,那么可以用如下操作获得第二个文本框的句柄。 // IntPtr htextbox2 = FindWindowEx(hwnd, htextbox, "EDIT", null);//填上次获得的句柄,可以得到下一个的句柄。 IntPtr htextbox21= FindWindowEx(htextbox, IntPtr.Zero, "wxWindowClassNR", null);//第二层第一个窗口//没问题 IntPtr htextbox22 = FindWindowEx(htextbox, htextbox21, "wxWindowClassNR", null);//第二层第二个窗口//没问题 IntPtr htextbox31 = FindWindowEx(htextbox22, IntPtr.Zero, "wxWindowClassNR", null);//3.1没问题 IntPtr htextbox32 = FindWindowEx(htextbox22, htextbox31, "wxWindowClassNR", null);//3.2没问题 IntPtr htextbox41 = FindWindowEx(htextbox32, IntPtr.Zero, "wxWindowClassNR", null);//4.1//000A105E//659550 IntPtr htextbox51 = FindWindowEx(htextbox41, IntPtr.Zero, "wxWindowClassNR", null);//5.1//0012101C//1183772 IntPtr htextbox52 = FindWindowEx(htextbox41, htextbox51, "wxWindowClassNR", null);//5.2 IntPtr htextbox61 = FindWindowEx(htextbox52, IntPtr.Zero, "wxWindowClassNR", null);//6.1 IntPtr htextbox71 = FindWindowEx(htextbox61, IntPtr.Zero, "wxWindowClassNR", null);//7.1 //8.1和8.2为目标,8.1为文本框,8.2为send按钮 IntPtr htextbox81 = FindWindowEx(htextbox71, IntPtr.Zero, "Edit", null);//8.1 IntPtr htextbox82= FindWindowEx(htextbox71, IntPtr.Zero, "Button", null);//8.2 SendMessage(htextbox81, WM_SETTEXT, IntPtr.Zero, "123232");//发送消息 SendMessage(htextbox82, WM_LBUTTONDOWN, IntPtr.Zero, null);//鼠标按下按钮 SendMessage(htextbox82, WM_LBUTTONUP, IntPtr.Zero, null);//释放鼠标 SendMessage(htextbox81, WM_INITDIALOG, IntPtr.Zero, null); SendMessage(htextbox81, WM_SETTEXT, IntPtr.Zero, "\t");//发送消息 }

IntPtr hwnd = FindWindow("wxWindowClassNR", "Pronterface");

第一行用了FindWindow方法,用来获取顶层窗口的句柄,获得到的句柄存在hwnd中,可以打印出来看结果,打印出来的是十进制的,spy++里看到的是十六进制的。FindWindow中的第一项是类名,第二项为窗口的标题,一般只用标题即可。下面这样写也可以。

IntPtr hwnd = FindWindow(null, "Pronterface");

接下来就是FindWindowEx方法,查找子窗口。

IntPtr htextbox21= FindWindowEx(htextbox, IntPtr.Zero, "wxWindowClassNR", null);//第二层第一个窗口//没问题 IntPtr htextbox22 = FindWindowEx(htextbox, htextbox21, "wxWindowClassNR", null);//第二层第二个窗口//没问题

FindWindowEx方法有四项,第一项是父级窗口的句柄,就是你想要在哪个大窗口下找。父级和子级是相对的,从外到里,就像剥洋葱,外面就是里面的父,而里面的窗口就是外面窗口的子。

第二项填的内容是个句柄。例如上面的两行代码,如果是IntPtr.Zero,那要找的窗口就是htextbox这个父级窗口下的第一个子窗口,如果是htextbox21,那么要找的窗口就是在htextbox这个父级窗口下,排在htextbox21的下面的一个窗口。以此类推。

第三项为要查找的控件的类名,可以在spy++上查找具体控件的类名

第四项为要查找的子窗口的名字,可以为null。

获取到了句柄值就可以对他们进行操作了。然后介绍SendMessage这个方法,这个方法有四个参数。

SendMessage(htextbox81, WM_SETTEXT, IntPtr.Zero, "123232");//发送消息 SendMessage(htextbox82, WM_LBUTTONDOWN, IntPtr.Zero, null);//鼠标按下按钮 SendMessage(htextbox82, WM_LBUTTONUP, IntPtr.Zero, null);//释放鼠标 SendMessage(htextbox81, WM_SETTEXT, IntPtr.Zero, "\t");//发送消息

第一个参数就是要操作的窗口的句柄,第二项就是要操作什么,不同的值会产生不同的操作。第三项一般为IntPtr.Zero。第四项一般为null,如果是向文本框发送消息,那么第四项就是要发送的字符。

第二项的参数需要提前定义,具体完整的指令表需要去查,这里只提供了一些:

const int WM_INITDIALOG = 0x0110;//初始化 const int WM_SETTEXT = 0x000C;//发送消息 const int WM_LBUTTONDOWN = 0x0201;//按下鼠标左键 const int WM_LBUTTONUP = 0x0202;//释放鼠标左键 const int WM_LBUTTONDBLCLK = 0x203; //双击鼠标左键 const int WM_RBUTTONDOWN = 0x204;//按下鼠标右键 const int WM_RBUTTONUP = 0x205;//释放鼠标右键 const int WM_RBUTTONDBLCLK = 0x206;//双击鼠标右键

这个第二项有点类似于单片机寄存器的值,设置不同的值,会有不同的功能。

我是控制的一个名字为Pronterface的软件,建的winform程序,添加了一个按钮,和两个文本框,文本框用来测试获取的句柄是否正确。然后附上完整代码:

using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows.Forms; using System.Runtime.InteropServices; using System.Diagnostics; using static System.Windows.Forms.VisualStyles.VisualStyleElement; using System.Xml.Linq; using static System.Windows.Forms.VisualStyles.VisualStyleElement.ToolBar; namespace WindowsFormsApp28 { public partial class Form1 : Form { public Form1() { InitializeComponent(); } [DllImport("User32.dll", EntryPoint = "FindWindow")] private static extern IntPtr FindWindow(string lpClassName, string lpWindowName); [DllImport("User32.dll", EntryPoint = "FindWindowEx")] private static extern IntPtr FindWindowEx(IntPtr hwndParent, IntPtr hwndChildAfter, string lpClassName, string lpWindowName); [DllImport("User32.dll", EntryPoint = "SendMessage")] private static extern int SendMessage(IntPtr hWnd, int Msg, IntPtr wParam, string lParam); //分隔符,以下几个常量放入事件中可用 const int WM_INITDIALOG = 0x0110;//初始化 const int WM_SETTEXT = 0x000C; const int WM_LBUTTONDOWN = 0x0201;//按下鼠标左键 const int WM_LBUTTONUP = 0x0202;//释放鼠标左键 const int WM_CLOSE = 0x0010; const int WM_LBUTTONDBLCLK = 0x203; //双击鼠标左键 const int WM_RBUTTONDOWN = 0x204;//按下鼠标右键 const int WM_RBUTTONUP = 0x205;//释放鼠标右键 const int WM_RBUTTONDBLCLK = 0x206;//双击鼠标右键 private void button1_Click(object sender, EventArgs e) { IntPtr hwnd = FindWindow("wxWindowClassNR", "Pronterface"); //FindWindow只查找顶层窗口 IntPtr htextbox = FindWindowEx(hwnd, IntPtr.Zero, "wxWindowClassNR", null);//(当前为第一层)IntPtr.Zero则表示获得第一个子窗口。第三个参数表示你需要找的子窗口的类型,第四个参数一般为null。 //如果一个窗口中有两个文本框,那么可以用如下操作获得第二个文本框的句柄。 // IntPtr htextbox2 = FindWindowEx(hwnd, htextbox, "EDIT", null);//填上次获得的句柄,可以得到下一个的句柄。 IntPtr htextbox21= FindWindowEx(htextbox, IntPtr.Zero, "wxWindowClassNR", null);//第二层第一个窗口//没问题 IntPtr htextbox22 = FindWindowEx(htextbox, htextbox21, "wxWindowClassNR", null);//第二层第二个窗口//没问题 IntPtr htextbox31 = FindWindowEx(htextbox22, IntPtr.Zero, "wxWindowClassNR", null);//3.1没问题 IntPtr htextbox32 = FindWindowEx(htextbox22, htextbox31, "wxWindowClassNR", null);//3.2没问题 IntPtr htextbox41 = FindWindowEx(htextbox32, IntPtr.Zero, "wxWindowClassNR", null);//4.1//000A105E//659550 IntPtr htextbox51 = FindWindowEx(htextbox41, IntPtr.Zero, "wxWindowClassNR", null);//5.1//0012101C//1183772 IntPtr htextbox52 = FindWindowEx(htextbox41, htextbox51, "wxWindowClassNR", null);//5.2 IntPtr htextbox61 = FindWindowEx(htextbox52, IntPtr.Zero, "wxWindowClassNR", null);//6.1 IntPtr htextbox71 = FindWindowEx(htextbox61, IntPtr.Zero, "wxWindowClassNR", null);//7.1 //8.1和8.2为目标,8.1为文本框,8.2为send按钮 IntPtr htextbox81 = FindWindowEx(htextbox71, IntPtr.Zero, "Edit", null);//8.1 IntPtr htextbox82= FindWindowEx(htextbox71, IntPtr.Zero, "Button", null);//8.2 textBox1.Text = (""+htextbox81); textBox2.Text = ("" + htextbox82); SendMessage(htextbox81, WM_SETTEXT, IntPtr.Zero, "123232");//发送消息 SendMessage(htextbox82, WM_LBUTTONDOWN, IntPtr.Zero, null);//鼠标按下按钮 SendMessage(htextbox82, WM_LBUTTONUP, IntPtr.Zero, null);//释放鼠标 SendMessage(htextbox81, WM_INITDIALOG, IntPtr.Zero, null); SendMessage(htextbox81, WM_SETTEXT, IntPtr.Zero, "\t");//发送消息 } } }



【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有