有时候想要通过软件的方式去控制别人软件的运行乃至控制别人软件上按钮的动作、文本框的填充等,实现自己独特的功能,怎么实现呢?
在Windows中不管是窗体、控件都有一个与之对应的句柄,只要获得了句柄,就可以操作该句柄对应的对象。
在VS中新建项目WinApp1,解决方案名为WinFormCall,再添加项目WinApp2.
重命名WinApp1中的Form1为WinApp1Form1,重命名WinApp2中的Form1为WinApp2Form1,同时将WinApp1Form1窗体的标题改为WinApp1Form,窗体WinApp1Form2标题改为WinApp2Form。
在WinApp1项目下添加WinApi处理类WinMsgHandle.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Runtime.InteropServices;
namespace WinApp1
{
public class WinMsgHandle
{
///
/// System defined message
///
public const int WM_COPYDATA = 0x004A;
///
/// User defined message
///
public const int WM_DATA_TRANSFER = 0x0437;
public const int WM_GETTEXT = 0x000D;
public const int WM_SETTEXT = 0x000C;
public const int WM_CLICK = 0x00F5;
public const int WM_KEYDOWN = 0x100;
public const int WM_KEYUP = 0x101;
[DllImport("User32.dll", EntryPoint = "FindWindow")]
public static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
[DllImport("user32.dll", EntryPoint = "FindWindowEx", SetLastError = true)]
public static extern IntPtr FindWindowEx(IntPtr hwndParent, IntPtr hwndChildAfter, string lpszClass, string lpszWindow);
// IsWindow method, using Windows API
[DllImport("User32.dll", EntryPoint = "IsWindow")]
public static extern bool IsWindow(int hWnd);
[DllImport("User32.dll", EntryPoint = "SendMessage", SetLastError = true)]
public static extern int SendMessage(IntPtr hWnd, int Msg, IntPtr wParam, string lParam);
[DllImport("user32.dll", EntryPoint = "SetForegroundWindow", SetLastError = true)]
public static extern void SetForegroundWindow(IntPtr hwnd);
}
}
在WinApp1Form1上放上一个文本框(name为TB_win1)、按钮(设置窗体2文本框,name为SETWin2TxtButton)、按钮(弹出对话框,name为Win1ButtonShowDialog)、按钮(WinForm2点击,name为B_Win2Click),如下
同WinApp1Form1,WinApp1Form2上放上一个文本框(name为TB_win2)、按钮(设置窗体1文本框,name为SETWin1TxtButton)、按钮(弹出对话框,name为Win2ButtonShowDialog)、按钮(WinForm1点击,name为B_Win1Click)、按钮(窗体1触发F1功能键,B_winF1),如下
整体思路为单击设置窗体2文本框将窗体2中TB_win2文本框的内容设置为窗体1中TB_win1中的文本,窗体1单击弹出对话框按钮则弹出一个对话框,单击WinForm2点击则触发窗体2中弹出对话框按钮的点击事件,按下F1功能键弹出对话框。同窗体1,窗体2没有F1功能键,但可以触发窗体1的F1功能键事件。
WinApp1Form1.cs代码如下
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.Diagnostics;
namespace WinApp1
{
public partial class WinApp1Form1 : Form
{
string lpszParentClass = "#32770"; //整个窗口的类名
string targetwinname = "WinApp2Form";
string lpszClass = "WindowsForms10.EDIT.app.0.141b42a_r9_ad1";
public WinApp1Form1()
{
InitializeComponent();
}
private void WinApp1Form1_Load(object sender, EventArgs e)
{
this.KeyPreview = true;
}
private void SETWin2TxtButton_Click(object sender, EventArgs e)
{
string lpszEditName = ""; //需要查找的输入框
IntPtr maindHwnd = WinMsgHandle.FindWindow(null, targetwinname); //获取窗体句柄
if (maindHwnd == IntPtr.Zero)
{
string strError = string.Format("SendMessageToTargetWindow: The target window [{0}] was not found!", targetwinname);
MessageBox.Show(strError, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
Debug.WriteLine(strError);
return;
}
else
{
IntPtr childHwnd = WinMsgHandle.FindWindowEx(maindHwnd, IntPtr.Zero, lpszClass, null); //获得输入框的句柄
if (childHwnd == IntPtr.Zero)
{
MessageBox.Show("子控件未找到", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
else
{
WinMsgHandle.SetForegroundWindow(maindHwnd);
WinMsgHandle.SendMessage(childHwnd, WinMsgHandle.WM_SETTEXT, IntPtr.Zero, TB_win1.Text); //鼠标点击的消息,对于各种消息的数值,大家还是得去API手册
}
}
}
private void Win1ButtonShowDialog_Click(object sender, EventArgs e)
{
MessageBox.Show("WinApp1 点击事件");
}
private void B_Win2Click_Click(object sender, EventArgs e)
{
string lpszClass_Submit = "WindowsForms10.BUTTON.app.0.141b42a_r9_ad1"; //需要查找的Button的类名
string lpszName_Submit = "弹出对话框"; //需要查找的Button的标题
IntPtr maindHwnd = WinMsgHandle.FindWindow(null, targetwinname); //获取窗体句柄
if (maindHwnd == IntPtr.Zero)
{
string strError = string.Format("SendMessageToTargetWindow: The target window [{0}] was not found!", targetwinname);
MessageBox.Show(strError, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
Debug.WriteLine(strError);
return;
}
else
{
IntPtr childHwnd = WinMsgHandle.FindWindowEx(maindHwnd, IntPtr.Zero, null, lpszName_Submit); //获得按钮的句柄
if (childHwnd == IntPtr.Zero)
{
MessageBox.Show("子控件未找到", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
else
{
WinMsgHandle.SetForegroundWindow(maindHwnd);
WinMsgHandle.SendMessage(childHwnd, WinMsgHandle.WM_CLICK, IntPtr.Zero, null);
}
}
}
private void WinApp1Form1_KeyDown(object sender, KeyEventArgs e)
{
Debug.Print(e.KeyValue.ToString());
if (e.KeyCode == Keys.F1) {
MessageBox.Show("WinApp1Form 按下F1");
}
}
}
}
WinApp2Form1.cs代码如下
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.Diagnostics;
using WinApp1;
namespace WinApp2
{
public partial class WinApp2Form1 : Form
{
string lpszParentClass = "#32770"; //整个窗口的类名
string targetwinname = "WinApp1Form";
string lpszClass = "WindowsForms10.EDIT.app.0.141b42a_r9_ad1";
public WinApp2Form1()
{
InitializeComponent();
}
private void WinApp2Form1_Load(object sender, EventArgs e)
{
}
private void SETWin1TxtButton_Click(object sender, EventArgs e)
{
string lpszEditName = ""; //需要查找的输入框
IntPtr maindHwnd = WinMsgHandle.FindWindow(null, targetwinname); //获取窗体句柄
if (maindHwnd == IntPtr.Zero)
{
string strError = string.Format("SendMessageToTargetWindow: The target window [{0}] was not found!", targetwinname);
MessageBox.Show(strError, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
Debug.WriteLine(strError);
return;
}
else
{
IntPtr childHwnd = WinMsgHandle.FindWindowEx(maindHwnd, IntPtr.Zero, lpszClass, null); //获得输入框的句柄
if (childHwnd == IntPtr.Zero)
{
MessageBox.Show("子控件未找到", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
else
{
WinMsgHandle.SetForegroundWindow(maindHwnd);
WinMsgHandle.SendMessage(childHwnd, WinMsgHandle.WM_KEYDOWN, IntPtr.Zero, null);
}
}
}
private void Win2ButtonShowDialog_Click(object sender, EventArgs e)
{
MessageBox.Show("WinApp2 点击事件");
}
private void B_Win1Click_Click(object sender, EventArgs e)
{
string lpszClass_Submit = "WindowsForms10.BUTTON.app.0.141b42a_r9_ad1"; //需要查找的Button的类名
string lpszName_Submit = "弹出对话框"; //需要查找的Button的标题
IntPtr maindHwnd = WinMsgHandle.FindWindow(null, targetwinname); //获取窗体句柄
if (maindHwnd == IntPtr.Zero)
{
string strError = string.Format("SendMessageToTargetWindow: The target window [{0}] was not found!", targetwinname);
MessageBox.Show(strError, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
Debug.WriteLine(strError);
return;
}
else
{
IntPtr childHwnd = WinMsgHandle.FindWindowEx(maindHwnd, IntPtr.Zero, null, lpszName_Submit); //获得按钮的句柄
if (childHwnd == IntPtr.Zero)
{
MessageBox.Show("子控件未找到", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
else
{
WinMsgHandle.SetForegroundWindow(maindHwnd);
WinMsgHandle.SendMessage(childHwnd, WinMsgHandle.WM_CLICK, IntPtr.Zero, null);
}
}
}
private void B_winF1_Click(object sender, EventArgs e)
{
IntPtr VK_F1 = new IntPtr(112);
IntPtr maindHwnd = WinMsgHandle.FindWindow(null, targetwinname); //获取窗体句柄
if (maindHwnd == IntPtr.Zero)
{
string strError = string.Format("SendMessageToTargetWindow: The target window [{0}] was not found!", targetwinname);
MessageBox.Show(strError, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
Debug.WriteLine(strError);
return;
}
else {
WinMsgHandle.SetForegroundWindow(maindHwnd);
WinMsgHandle.SendMessage(maindHwnd, WinMsgHandle.WM_KEYDOWN, VK_F1, TB_win2.Text);
}
}
}
}
WinApp1和WinApp2编译后,同时运行两个窗体。
在窗体1文本框中输入“hello,我是窗体1的文本框”,点击设置窗体2文本框,结果如下,在窗体2中输入文本点击设置窗体1文本框效果一样。
在窗体1中点击弹出对话框按钮,如下(同效果在窗体2中点击WinForm1点击)