C#-使用Win32_API的SendMessage实现指定窗口的模拟点击操作
Posted 青丝·旅人
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了C#-使用Win32_API的SendMessage实现指定窗口的模拟点击操作相关的知识,希望对你有一定的参考价值。
这些天因为需求原因,要实现指定窗口的点击操作。因为是萌新,所以我只能在度娘的帮助下,一步步实现这个简单的功能。(使用API方法需引入System.Runtime.InteropServices命名空间)
(注:该情景我已获取了我需要操作窗口的句柄,如要自行获取请使用Win32API下的FindWindow方法与FindWindowEx方法)
1.过程中绕了许多弯路
最开始是想通过Win32API下的mouse_event来实现鼠标的模拟点击的操作,但用此方法需要先用SetForegroudWindow方法将窗口置顶,然后再使用mouse_event方法来进行点击;这种操作并不是我理想中的效果。
这种方式是通过模拟前台鼠标点击,先将所需操作的窗口置前,然后通过鼠标事件模拟点击操作进行点击。很遗憾,我使用这种方法并没有执行成功,后来我了解到这种方法需要配合几个其他的API方法使用。
using System.Runtime.InteropServices; private static int MOUSEEVENTF_MOVE = 0x0001; //移动鼠标 private static int MOUSEEVENTF_LEFTDOWN = 0x0002; //模拟鼠标左键按下 private static int MOUSEEVENTF_LEFTUP = 0x0004; //模拟鼠标左键抬起 private static int MOUSEEVENTF_RIGHTDOWN = 0x0008; //模拟鼠标右键按下 private static int MOUSEEVENTF_RIGHTUP = 0x0010; //模拟鼠标右键抬起 private static int MOUSEEVENTF_MIDDLEDOWN = 0x0020; //模拟鼠标中键按下 private static int MOUSEEVENTF_MIDDLEUP = 0x0040; //模拟鼠标中键抬起 private static int MOUSEEVENTF_ABSOLUTE = 0x8000; //标示是否采用绝对坐标 [DllImport("user32.dll")] public static extern bool SetForegroundWindow(IntPtr hWnd);//指定句柄窗口置前 [System.Runtime.InteropServices.DllImport("user32")] public static extern int mouse_event(int dwFlags, int dx, int dy, int cButtons, int dwExtraInfo);//https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-mouse_event 有参数详解 SetForegroundWindow(new IntPtr(窗口句柄)); mouse_event(MOUSEEVENTF_LEFTDOWN | MOUSEEVENTF_LEFTUP, x, y, 0, 0);
2.然后我便又接触到SetCursorPos这个API方法、并在大佬博客知识海领悟出了MoveMouseToPoint、SetMouseRectangle、SetMouseAtCenterScreen等方法,继而再次挑战我的目标。
原理是先通过SetCursorPos设置鼠标光标的位置,然后通过MoveMouseToPoint移动鼠标到指定位置,再通过mouse_event进行点击
其实这个点击方式与第一种方法大同小异,无非是多了一个设置鼠标位置的过程,虽然这此完成了我所要的点击效果,却没有达到我的真正的目的。
using System.Runtime.InteropServices; public class MouseClick { /// <summary> /// 引用user32.dll动态链接库(windows api), /// 使用库中定义 API:SetCursorPos /// </summary> [DllImport("user32.dll")] private static extern int SetCursorPos(int x, int y); /// <summary> /// 移动鼠标到指定的坐标点 /// </summary> /// <param name="p">移动的点位</param> public void MoveMouseToPoint(Point p) { SetCursorPos(p.X, p.Y); } /// <summary> /// 设置鼠标的移动范围 /// </summary> /// <param name="rectangle">移动范围的矩阵</param> public void SetMouseRectangle(Rectangle rectangle) { System.Windows.Forms.Cursor.Clip = rectangle; } /// <summary> /// 中心坐标x或y /// </summary> public static int loginx, loginy; /// <summary> /// 设置鼠标位于屏幕中心 /// </summary> public void SetMouseAtCenterScreen() { //当前屏幕的宽高 int winHeight = System.Windows.Forms.Screen.PrimaryScreen.WorkingArea.Height; int winWidth = System.Windows.Forms.Screen.PrimaryScreen.WorkingArea.Width; //设置鼠标的x,y位置 loginx = winWidth / 3 * 2; loginy = winHeight / 4 + 5; Point centerP = new Point(loginx, loginy); //移动鼠标 MoveMouseToPoint(centerP); } public const int MOUSEEVENTF_LEFTDOWN = 0x2;//左键按下 public const int MOUSEEVENTF_LEFTUP = 0x4;//左键弹起 public enum MouseEventFlags { Move = 0x0001, //移动鼠标 LeftDown = 0x0002,//模拟鼠标左键按下 LeftUp = 0x0004,//模拟鼠标左键抬起 RightDown = 0x0008,//鼠标右键按下 RightUp = 0x0010,//鼠标右键抬起 MiddleDown = 0x0020,//鼠标中键按下 MiddleUp = 0x0040,//中键抬起 Wheel = 0x0800, Absolute = 0x8000//标示是否采用绝对坐标 } /// <summary> /// 鼠标事件 /// </summary> /// <param name="dwFlags">鼠标操作指令</param> /// <param name="dx">操作点x</param> /// <param name="dy">操作点y</param> /// <param name="cButtons">参数1</param> /// <param name="dwExtraInfo">参数2</param> [DllImport("User32")] public extern static void mouse_event(int dwFlags, int dx, int dy, int cButtons, int dwExtraInfo); /// <summary> /// 鼠标左键点击屏幕中心 /// </summary> public void MouseClick_CenterScree() { SetMouseAtCenterScreen(); mouse_event(MOUSEEVENTF_LEFTDOWN | MOUSEEVENTF_LEFTUP, loginx, loginy, 0, 0); //mouse_event(MOUSEEVENTF_LEFTDOWN | MOUSEEVENTF_LEFTUP, loginx, loginy, 0, 0);//点击第二次 } }
3.经过这两此的资料捞取代码实验,我发现mouse_event是不能达到我想要的效果的,于是我便把目光投向了一个新的API方法,那便是SendMessage(windows系统信息交互方法)。
SendMessage的执行原理是:将执行的操作消息发送到一个或多个窗口,函数方法调用指定窗口的窗口过程,执行窗口过程处理完成该操作消息,最后执行返回。
该函数方法原型是↓
LRESULT SendMessage(HWND hwnd, UINT Msg, WPARAM wParam, LPARAM lParam)
属于User32.dll中的函数方法。具体参数详解请参照:SendMessage参数详解
刚接触这个函数方法,也没有立刻解决指定模拟点击的问题;因为SendMessage用法有许多,光是参数Msg就包含了许多种。SendMessage发送消息类型(Msg)
最后在不断的度娘帮助下,完成了我想要的效果
(注:因为在此消息类型中,坐标y的值属于高位,所以要右移16位变为高位数)
using System.Runtime.InteropServices public class Mouer_Click { [DllImport("user32.dll", EntryPoint = "SendMessageA")] public static extern int SendMessage(IntPtr hwnd, int wMsg, IntPtr wParam, IntPtr lParam); SendMessage(new IntPtr(窗口句柄), 0x202, IntPtr.Zero, new IntPtr(x + (y << 16))); }
虽然过程非常的坎坷,但是最终还是实现了我想要的效果。非常开心与大家分享此次模拟点击的经验,希望学C#大家能在这篇随笔的帮助下,不像我一样,少走一些弯路,感谢您观赏!
以上是关于C#-使用Win32_API的SendMessage实现指定窗口的模拟点击操作的主要内容,如果未能解决你的问题,请参考以下文章
使用 Win32 API 的 Windows“真实”用户列表
如何使用 WIN32 C/C++ API 告诉 Windows 10 平铺、居中或拉伸桌面壁纸?