c# 获取窗体句柄后 根据坐标向指定区域模拟鼠标点击

小菜来袭 2018-10-28 06:31:08
最近在做个新项目 业主希望能通过QQ收到软件的预警消息

1:首页获取QQ的聊天句柄就是说必须要打开一个聊天框
2:然后获取到语音通话的X,Y位置 再用模拟鼠标点击 发起语音通话

句柄和X,Y的位置我已经获取到了

// 获得窗口矩形
[DllImport("user32.dll")]
public static extern int GetWindowRect(IntPtr hWnd, out RECT lpRect);
// 获得客户区矩形
[DllImport("user32.dll")]
public static extern int GetClientRect(IntPtr hWnd, out RECT lpRect);
// 矩形结构
[StructLayout(LayoutKind.Sequential)]
public struct RECT
{
public int Left;//80
public int Top;//450
public double Right;//800
public int Bottom;
}

句柄 IntPtr hwnd = aa;//aa是QQ的句柄23577

我在知道句柄和坐标后 怎么模拟鼠标点击那个坐标区域呢?

...全文
1613 8 打赏 收藏 转发到动态 举报
AI 作业
写回复
用AI写文章
8 条回复
切换为时间正序
请发表友善的回复…
发表回复
assky124 2018-10-29
  • 打赏
  • 举报
回复
感觉你需求都搞错了,只是发通知,应该有相应的API接口的,微信可以申请公众号。少量用户可以用测试号(不保险),多的申请一个公众号,一年300而已。 QQ好像也有相应的功能的
小菜来袭 2018-10-29
  • 打赏
  • 举报
回复
嗯的 确实是坑 就在刚才电话说了软件加上个通过微信通知 的功能
大狗狗 2018-10-28
  • 打赏
  • 举报
回复
windows版本、QQ版本都可能影响到mouse_event的效果。QQ窗口也不是用标准windows控件堆成的,而是完全自定义的窗体。

你是给客户设计产品,而不是自己验证技术。所以建议不要采用这种方法,因为不靠谱。你的代码会很复杂,你需要考虑很多情况,但即使如此还是不能保证应用中的可靠性。这是一个坑。

腾迅产品应该提供了一些接口供开发者使用,你看看QQ有没提供相应接口,然后去调用实现需要功能。
小菜来袭 2018-10-28
  • 打赏
  • 举报
回复
只能是吧
引用 3 楼 Win32FanEx 的回复:
需要引入win32API来实现。windows7及以下版本亲测可行,更高版本windows没试过。

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);

        SetForegroundWindow(hwnd_qq);
        mouse_event(MOUSEEVENTF_LEFTDOWN | MOUSEEVENTF_LEFTUP, x_qq, y_qq, 0, 0);
加个SetForegroundWindow是为了确保窗口置顶。
引用 3 楼 Win32FanEx 的回复:
需要引入win32API来实现。windows7及以下版本亲测可行,更高版本windows没试过。

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);

        SetForegroundWindow(hwnd_qq);
        mouse_event(MOUSEEVENTF_LEFTDOWN | MOUSEEVENTF_LEFTUP, x_qq, y_qq, 0, 0);
加个SetForegroundWindow是为了确保窗口置顶。
我要把窗体覆盖QQ窗体 在QQ窗体上我的那个按钮 重叠和QQ语音按钮 点击才会有用 为什么呢
小菜来袭 2018-10-28
  • 打赏
  • 举报
回复
我是在窗口内实现的点击 应该跟句柄有关系吧 IntPtr hwnd = aa; // QQ窗口句柄 SetForegroundWindow(hwnd); RECT rc; GetWindowRect(hwnd, out rc); GetClientRect(hwnd, out rc); mouse_event(MOUSEEVENTF_LEFTDOWN | MOUSEEVENTF_LEFTUP, 350, 70, 0, 0); 没有发生点击效果 350和70 是X和Y
大狗狗 2018-10-28
  • 打赏
  • 举报
回复
需要引入win32API来实现。windows7及以下版本亲测可行,更高版本windows没试过。


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);

SetForegroundWindow(hwnd_qq);
mouse_event(MOUSEEVENTF_LEFTDOWN | MOUSEEVENTF_LEFTUP, x_qq, y_qq, 0, 0);


加个SetForegroundWindow是为了确保窗口置顶。
hwyqy 2018-10-28
  • 打赏
  • 举报
回复
应用实例
以下从实用的角度出发,援引笔者在实际工作开发中的API应用一例,谨供参考。
 
漫游过Windows
3.2的五分钟教程的用户,大概还记得演示鼠标用法。鼠标指针自动随教程的指令移动,自动点开菜单、按动按钮,完全脱离了对物理鼠标器的依赖。这种高级控制技巧在VB的函数和方法中是找不到的,仍然要借助于API函数。

 本例用API函数实现对鼠标的“遥控”:无论鼠标指针在何处,一个菜单命令Alt-C就能使鼠标指针自动平滑移动到窗口中一个按钮的中心,然后自动按动按钮,激活按钮的Click事件处理过程。掌握了本例的方法后,前面提到的五分钟教程软件就不难制作了。本例中,以下几个功能的实现至关重要:获取鼠标光标在屏幕上的位置、获取按钮在屏幕上(注意:不是在窗口中)的位置、移动鼠标光标、自动按下和放开按钮,下面分别介绍。

获取鼠标光标在屏幕上的位置和移动鼠标光标,分别需调用API函数GetCursorPos和SetCursorPos。这两个函数的接口声明如下:Declare Function GetCursorPos Lib “user32" (lpPoint As POINTAPI) As Long
Declare Function SetCursorPos Lib “user32" (ByVal X As Long,ByVal Y As Long) As Long
在SetCursorPos函数中,参数X和Y指定了鼠标光标在屏幕上的坐标。GetCursorPos函数把鼠标光标的当前位置存到结构变量lpPoint中。结构变量的定义如下:
Private Type POINTAPI
X As Long
Y As Long
End Type

按钮的Left和Top属性给出的是按钮的左上角在窗口客户区坐标系中的坐标位置。要把鼠标光标移到按钮正中,需要得到按钮中心在屏幕坐标系中的坐标位置。窗口客户区坐标系与屏幕坐标系不仅坐标原点不同,二者的坐标单位(scale)也不同。窗口客户区坐标系的单位是Twip,屏幕坐标系单位是Pixel,二者的关系可以从屏幕对象Screen的TwipsPerPixelX和TwipsPerPixelY属性获取。这两个属性分别代表了水平和垂直两个方向上的单位转换比例。

 
把按钮中心在窗口客户区中的坐标单位转换为屏幕坐标系的单位后,还通过一个API函数进行坐标平移变换,最终取得按钮中心在屏幕坐标系中的坐标位置。这个API函数的接口声明如下:

 
Declare Function ClientToScreen Lib “user32" (ByVal hwnd As Long, lpPoint As POINTAPI) As Long
最后一步是自动按下和放开按钮,这是通过模拟鼠标左键的按下和放开来实现的。该功能需调用API函数SendMessage向按钮发一对鼠标左键按下和放开的消息,函数接口声明如下:

Declare Function SendMessage Lib “user32" Alias“SendMessageA" (ByVal hwnd As Long, ByVal wMsg As Long, ByVal wParam As Long, lParam As Any) As Long
SendMessage函数的hwnd参数为接收消息的窗口或控件的hwnd句柄。wMsg参数指定具体的消息值。在本例中,要发送鼠标左键按下和释放的消息,wMsg的取值分别为WM_LBUTTONDOWN和WM_LBUTTONUP,这两个常量定义如
下:
Const WM_LBUTTONDOWN = &H201
Const WM_LBUTTONUP = &H202

 
把这两个消息发送给一个按钮,按钮就会像真的被鼠标左键单击了一样? SendMessage函数中的后两个参数在本例中可以不理,简单置0即可。

 
还有一点细节需注意。如果连续给按钮发送一对WM_LBUTTONDOWN和WM_LBUTTONUP消息,Windows会来不及进行一些必要的系统操作,这样在视觉上就看不出按钮被按下后又放开的效果,好像按钮没有按动。但按钮的Click事件处理过程被激活执行表明按钮确实被按过。为了达到视觉上的完美效果,我们不妨在WM_LBUTTONDOWN和WM_LBUTTONUP两个消息之间插入一段短短的延时,比如说200毫秒,在这段延时期间,把处理权交给Windows,这样Windows就有时间显示按钮被按下的效果了。插入延时的办法有很多,可以加入一段空循环或利用计时器控件,这里再介绍一个API函数GetTickCount,该函数获取自Windows启动至被调用时所经过的毫秒数。利用这个函数控制延时,不仅精确,而且节省资源。GetTickCount函数的接口声明如下: 
hwyqy 2018-10-28
  • 打赏
  • 举报
回复
以前用VB的时候做过,不知道现在的Windows系统对权限是不是有讲究

可以用mouse_event API函数来模拟鼠标在某个位置Click

Private Declare Sub mouse_event Lib "user32" (ByVal dwFlags As Long, ByVal dx As Long, ByVal dy As Long, ByVal cButtons As Long, ByVal dwExtraInfo As Long)
Private Const MOUSEEVENTF_ABSOLUTE = &H8000 ' absolute move
Private Const MOUSEEVENTF_LEFTDOWN = &H2 ' left button down
Private Const MOUSEEVENTF_LEFTUP = &H4 ' left button up
Private Const MOUSEEVENTF_MIDDLEDOWN = &H20 ' middle button down
Private Const MOUSEEVENTF_MIDDLEUP = &H40 ' middle button up
Private Const MOUSEEVENTF_MOVE = &H1 ' mouse move
Private Const MOUSEEVENTF_RIGHTDOWN = &H8 ' right button down
Private Const MOUSEEVENTF_RIGHTUP = &H10 ' right button up


Private Sub MouseClick(x As Long, y As Long)
Dim SCR_W As Long
Dim SCR_H As Long

SCR_W = Screen.Width / 15
SCR_H = Screen.Height / 15
'移动鼠标
mouse_event MOUSEEVENTF_ABSOLUTE Or MOUSEEVENTF_MOVE, Int(x / SCR_W * 65535), Int(y / SCR_H * 65535), 0, 0
'左键按下
mouse_event MOUSEEVENTF_LEFTDOWN, 0, 0, 0, 0
DoEvents
'左键放开
mouse_event MOUSEEVENTF_LEFTUP, 0, 0, 0, 0
DoEvents
End Sub

111,096

社区成员

发帖
与我相关
我的任务
社区描述
.NET技术 C#
社区管理员
  • C#
  • AIGC Browser
  • by_封爱
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

让您成为最强悍的C#开发者

试试用AI创作助手写篇文章吧