【问题标题】:Send right click to a window发送右键单击到窗口
【发布时间】:2019-12-04 16:02:42
【问题描述】:

我正在尝试将鼠标右键单击发送到指定坐标的窗口。

我用 2 个代码测试过

代码 1:

[DllImport("user32.dll")]
public static extern int SendMessage(IntPtr hWnd, int Msg, int wParam, int lParam);
[DllImport("user32.dll")]        
static extern bool ScreenToClient(IntPtr hWnd, ref POINT lpPoint);

public struct POINT
{
    public int x;
    public int y;
}

var client = Process.GetProcessesByName("client_dx");
var whandle = client.MainWindowHandle;

POINT point = new POINT();
point.x = 1836;
point.y = 325;
ScreenToClient(whandle, ref point);
int lparm = (point.x << 16) + point.y;    
int lngResult = SendMessage(whandle, 0x0204, 0, lparm);
int lngResult2 = SendMessage(whandle, 0x0205, 0, lparm);

代码 2:

[DllImport("user32.dll")]
public static extern int SendMessage(IntPtr hWnd, int Msg, int wParam, int lParam);
[DllImport("user32.dll")]        
static extern bool ScreenToClient(IntPtr hWnd, ref POINT lpPoint);

public struct POINT
{
    public int x;
    public int y;
}

public int MakeLParam(int LoWord, int HiWord)
{
    return (int)((HiWord << 16) | (LoWord & 0xFFFF));
}

var client = Process.GetProcessesByName("client_dx");
var whandle = client.MainWindowHandle;

POINT point = new POINT();
point.x = 1836;
point.y = 325;

ScreenToClient(whandle, ref point);

int lparm = MakeLParam(point.x, point.y);
int lngResult = SendMessage(whandle, 0x0204, 0, lparm);
int lngResult2 = SendMessage(whandle, 0x0205, 0, lparm);

它发送了一个右键单击但没有发送到正确的坐标,似乎它忽略了我在 LPARAM 中指定的坐标,因为如果我在窗口周围移动鼠标,它会在我放置鼠标指针但不在坐标中的任何地方点击我指定。

我已经测试过在代码 2 中更改这一行:

int lparm = MakeLParam(point.x, point.y);

到这个:

int lparm = (point.x << 16) + point.y;

但是不起作用,我得到了相同的结果...

【问题讨论】:

  • 您是否测试/检查了 ScreenToClient() 返回(通过 ref)到点结构的坐标?
  • 正如@VillageTech 所避免的那样,所使用的坐标是相对于您正在处理的客户端窗口,而不是整个桌面。在 WM_RBUTTONDOWN(/UP) 的文档中,它说“坐标相对于客户区的左上角。”
  • 如您所见,我正在将桌面坐标“转换”为客户端坐标。 ScreenToClient(whandle, ref point);但无论如何,如果是这种情况,它并不能解释为什么当我移动鼠标时右键单击区域会发生变化,它忽略了我的坐标
  • VillageTech 指的是您永远不会检查 ScreenToClient 返回的布尔值,以查看调用是成功还是失败。
  • 使用mouse_event

标签: c# .net winforms sendmessage right-click


【解决方案1】:

您可以使用SendMessagemouse_eventSendInput 执行鼠标操作。在这里我将分享一些关于前两者的细节和例子。

使用 SendMessage

  • SendMessage 无需移动光标即可执行鼠标操作。
  • SendMessage 需要窗口句柄才能发送消息。
  • SendMessage 将鼠标消息发送到窗口内的相对位置。坐标应相对于窗口客户区的左上角。
  • 如果您知道客户端坐标中的哪个点要发送点击,那么只需使用客户端坐标即可。通常是这样。
  • 如果你有一个屏幕位置并且你想把它翻译成客户端的相对位置,你可以使用ScreenToClient。但是由于您通常知道要单击的相对位置,因此通常不需要ScreenToClient
  • 要将参数传递给MakeLParam,低位字指定x坐标,高位字指定光标的y坐标。为了减少混淆,请使用以下函数:

    IntPtr MakeLParam(int x, int y) => (IntPtr)((y << 16) | (x & 0xFFFF));
    
  • 附带说明,如果您想将消息发送到窗口并在不等待线程处理消息的情况下返回,您可以使用PostMessage

使用 mouse_event

  • mouse_event 在当前光标位置执行鼠标操作。
  • 在调用mouse_event之前,您需要将光标移动到屏幕上您要执行点击的位置。
  • 要获取窗口客户点的屏幕位置,可以使用ClientToScreen 方法。
  • 要移动光标,您可以将Cursor.Position 设置为屏幕位置。
  • 建议改用SendInput函数。

示例 1 - 发送消息

使用SendMessage可以点击指定窗口的指定相对位置。在下面的示例中,我在notepad 主窗口中找到了edit 控件,然后我在编辑控件的客户矩形内右键单击(20,20) 坐标:

//using System;
//using System.Diagnostics;
//using System.Drawing;
//using System.Linq;
//using System.Runtime.InteropServices;
//using System.Windows.Forms;
const int WM_RBUTTONDOWN = 0x0204;
const int WM_RBUTTONUP = 0x0205;
const int WM_MOUSEMOVE = 0x0200;
[DllImport("User32.DLL")]
static extern int SendMessage(IntPtr hWnd, int Msg, IntPtr wParam, IntPtr lParam);

IntPtr MakeLParam(int x, int y) => (IntPtr)((y << 16) | (x & 0xFFFF));

[DllImport("user32.dll")]
static extern IntPtr FindWindowEx(IntPtr hwndParent, IntPtr hwndChildAfter,
    string lpszClass, string lpszWindow);

void PerformRightClick(IntPtr hwnd, Point point)
{
    var pointPtr = MakeLParam(point.X, point.Y);
    SendMessage(hwnd, WM_MOUSEMOVE, IntPtr.Zero, pointPtr);
    SendMessage(hwnd, WM_RBUTTONDOWN, IntPtr.Zero, pointPtr);
    SendMessage(hwnd, WM_RBUTTONUP, IntPtr.Zero, pointPtr);
}
void button1_Click(object sender, EventArgs e)
{
    var notepad = Process.GetProcessesByName("notepad").FirstOrDefault();
    if (notepad != null)
    {
        var edit = FindWindowEx(notepad.MainWindowHandle, IntPtr.Zero, "Edit", null);
        PerformRightClick(edit, new Point(20, 20));
    }
}

示例 2 - mouse_event

使用mouse_event可以点击当前鼠标位置。这意味着您需要将鼠标移动到所需的位置。在下面的示例中,我在notepad 主窗口中找到了edit 控件,然后我在编辑控件的客户矩形内右键单击(20,20) 坐标:

//using System;
//using System.Diagnostics;
//using System.Drawing;
//using System.Linq;
//using System.Runtime.InteropServices;
//using System.Windows.Forms;
const int MOUSEEVENTF_RIGHTDOWN = 0x0008;
const int MOUSEEVENTF_RIGHTUP = 0x0010;
[DllImport("user32.dll")]
static extern void mouse_event(uint dwFlags, uint dx, uint dy,
    uint cButtons, uint dwExtraInfo);

[DllImport("user32.dll")]
static extern IntPtr FindWindowEx(IntPtr hwndParent, IntPtr hwndChildAfter,
    string lpszClass, string lpszWindow);

[StructLayout(LayoutKind.Sequential)]
struct POINT { public int X; public int Y; }

[DllImport("user32.dll")]
static extern bool ClientToScreen(IntPtr hWnd, ref POINT lpPoint);

void PerformRightClick(IntPtr hwnd, Point p)
{
    POINT point = new POINT() { X = p.X, Y = p.Y };
    ClientToScreen(hwnd, ref point);
    Cursor.Position = new Point(point.X, point.Y);
    uint X = (uint)Cursor.Position.X;
    uint Y = (uint)Cursor.Position.Y;
    mouse_event(MOUSEEVENTF_RIGHTDOWN | MOUSEEVENTF_RIGHTUP, X, Y, 0, 0);
}
void button1_Click(object sender, EventArgs e)
{
    var notepad = Process.GetProcessesByName("notepad").FirstOrDefault();
    if (notepad != null)
    {
        var edit = FindWindowEx(notepad.MainWindowHandle, IntPtr.Zero, "Edit", null);
        PerformRightClick(edit, new Point(20, 20));
    }
}

【讨论】:

  • 您分配了赏金,谢谢。但没有接受/投票的答案。看起来答案有问题?如果我能帮助你,请告诉我:)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-01-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-01-23
相关资源
最近更新 更多