向窗口发送右键单击命令

3

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

我已经测试了两个代码

代码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()返回给点结构的坐标(通过引用)吗? - VillageTech
1
正如@VillageTech所暗示的那样,使用的坐标是相对于您正在处理的客户端窗口而不是整个桌面的。在WM_RBUTTONDOWN(/UP)的文档中,它说:“该坐标相对于客户区域的左上角。” - Señor CMasMas
使用 mouse_event - Reza Aghaei
或者如果您想使用SendMessage,请将窗口屏幕位置转换为其相对位置。 - Reza Aghaei
@kuhi 请查看下面答案中的工作示例 :) - Reza Aghaei
显示剩余4条评论
1个回答

7

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

使用 SendMessage

  • SendMessage performs the mouse action without needing to move the cursor.
  • SendMessage needs handle of the window to send message.
  • SendMessage sends the mouse message to a relative position inside the window. The coordinate should be relative to the upper-left corner of the client area of the window.
  • If you know which point in the client coordinate, you want to send click, then just use the client coordinates. It's usually the case.
  • If you have a screen position and you want to translate it to client relative position, you can use ScreenToClient. But since you usually know the relative position you are going to click, you usually don't need ScreenToClient.
  • To pass parameters to MakeLParam the low-order word specifies the x-coordinate and high-order word specifies the y-coordinate of the cursor. To make it less confusing, use the following function:

    IntPtr MakeLParam(int x, int y) => (IntPtr)((y << 16) | (x & 0xFFFF));
    
  • And as a side-note, if you want to the send the message to a window and return without waiting for the thread to process the message, you can use PostMessage.

使用mouse_event

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

示例1 - SendMessage

使用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));
    }
}

你设置了悬赏,谢谢。但是你没有接受/投票回答。看起来回答有问题?如果需要帮助,请告诉我 :) - Reza Aghaei
很好的解释@Reza - Sangeeth Nandakumar

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接