ClientToScreen API函数不返回预期的点

时间:2017-12-01 11:45:54

标签: c# winapi

我目前正在设计一个功能,可以搜索窗口图片上的子图片。如果搜索成功,则单击此子图片的中心。奇怪的是,它总是点击低于预期的位置。

搜索算法工作正常 - 我仍然检查它。提供的函数坐标是正确的。但ClientToScreen功能很奇怪。例如:

我的子图片是在x = 352,y = 70时发现的 - 坐标是相对于窗口的左上角。 窗口的左上角相对于屏幕位于x = 91,y = 303。 所以,我希望坐标相对于屏幕点击如下:

X_Click = Window.Left + X_Click_rel2Wnd = 352 + 91= 443;
Y_Click = Window.Top + Y_Click_rel2Wnd = 70 + 303 = 373;

该函数返回: 447/396

看起来这张照片显示: enter image description here

任何人都有想法,哪有错?

代码下方:

public static class ClickOnPointTool{
private const uint MOUSEEVENTF_LEFTDOWN = 0x02;
private const uint MOUSEEVENTF_LEFTUP = 0x04;
private const uint MOUSEEVENTF_RIGHTDOWN = 0x08;
private const uint MOUSEEVENTF_RIGHTUP = 0x10;
private const uint MOUSEEVENTF_MIDDLEDOWN = 0x00000020;
private const uint MOUSEEVENTF_MIDDLEUP = 0x00000040;

[System.Runtime.InteropServices.StructLayout(System.Runtime.InteropServices.LayoutKind.Sequential)]
public struct TPoint{
    public int X;
    public int Y;
}

[System.Runtime.InteropServices.DllImport("user32.dll")]
static extern bool ClientToScreen(System. IntPtr hWnd, ref TPoint lpPoint);

#pragma warning disable 649
internal struct INPUT{
    public System.UInt32 Type;
    public MOUSEKEYBDHARDWAREINPUT Data;
}

[System.Runtime.InteropServices.DllImport("user32.dll")]
internal static extern uint SendInput(uint nInputs, [System.Runtime.InteropServices.MarshalAs(System.Runtime.InteropServices.UnmanagedType.LPArray), System.Runtime.InteropServices.In] INPUT[] pInputs, int cbSize);

[System.Runtime.InteropServices.StructLayout(System.Runtime.InteropServices.LayoutKind.Explicit)]
internal struct MOUSEKEYBDHARDWAREINPUT{
    [System.Runtime.InteropServices.FieldOffset(0)]
    public MOUSEINPUT Mouse;
}

internal struct MOUSEINPUT{
    public System.Int32 X;
    public System.Int32 Y;
    public System.UInt32 MouseData;
    public System.UInt32 Flags;
    public System.UInt32 Time;
    public System.IntPtr ExtraInfo;
}

#pragma warning restore 649
public static void ClickOnPoint(System.IntPtr wndHandle, int x, int y, bool KeepCursor = false, bool RightButton = false, bool DoubleClick = false, System.Data.DataTable WndBoundings = null){
    int nTimes = 0;
    TPoint clientPoint;
    clientPoint.X = x;
    clientPoint.Y = y;

    System.Drawing.Point oldPos = System.Windows.Forms.Cursor.Position;

    //System.Windows.Forms.MessageBox.Show("Click to " + clientPoint.X + " / " + clientPoint.Y + "");
    if(DoubleClick){nTimes = 2;}else{nTimes = 1;}

    /// get screen coordinates
    if(WndBoundings == null){
        ClientToScreen(wndHandle, ref clientPoint);
    }else{
        clientPoint.X += (int)WndBoundings.Rows[0]["Left"];
        clientPoint.Y += (int)WndBoundings.Rows[0]["Top"];
    }
    //System.Windows.Forms.MessageBox.Show("Click to " + clientPoint.X + " / " + clientPoint.Y + "");

    /// set cursor on coords, and press mouse
    System.Windows.Forms.Cursor.Position = new System.Drawing.Point(clientPoint.X, clientPoint.Y);

    INPUT inputMouseDown = new INPUT();
    inputMouseDown.Type = 0; /// input type mouse
    if(RightButton){
        inputMouseDown.Data.Mouse.Flags = MOUSEEVENTF_RIGHTDOWN; ///right button down
    }else{
        inputMouseDown.Data.Mouse.Flags = MOUSEEVENTF_LEFTDOWN; /// left button down
    }
    INPUT inputMouseUp = new INPUT();
    inputMouseUp.Type = 0; /// input type mouse
    if(RightButton){
        inputMouseUp.Data.Mouse.Flags = MOUSEEVENTF_RIGHTUP; /// right button up
    }else{
        inputMouseUp.Data.Mouse.Flags = MOUSEEVENTF_LEFTUP; /// left button up
    }

    var inputs = new INPUT[] { inputMouseDown, inputMouseUp };

    for(int i=0;i<nTimes;i++){
        SendInput((uint)inputs.Length, inputs, System.Runtime.InteropServices.Marshal.SizeOf(typeof(INPUT)));
    }

    /// return mouse 
    if(!KeepCursor){System.Windows.Forms.Cursor.Position = oldPos;}
}

}

1 个答案:

答案 0 :(得分:1)

谢谢大家。运行良好:

    private static System.Drawing.Point GetWindowCornerLU(System.IntPtr hWnd){
    if(hWnd == System.IntPtr.Zero){throw new System.Exception("ERROR: Window handle is not referenced!");}

    WindowHandle.User32.Rect rect = new WindowHandle.User32.Rect();
    WindowHandle.User32.GetWindowRect(hWnd, ref rect);
    return new System.Drawing.Point(rect.left, rect.top);
}

#pragma warning restore 649
public static void ClickOnPoint(System.IntPtr wndHandle, int x, int y, bool KeepCursor = false, bool RightButton = false, bool DoubleClick = false){
    int nTimes = 0;
    TPoint clientPoint;
    clientPoint.X = x;
    clientPoint.Y = y;

    System.Drawing.Point oldPos = System.Windows.Forms.Cursor.Position;

    //System.Windows.Forms.MessageBox.Show("Click to " + clientPoint.X + " / " + clientPoint.Y + "");
    if(DoubleClick){nTimes = 2;}else{nTimes = 1;}

    /// get screen coordinates
    //ClientToScreen(wndHandle, ref clientPoint);
    System.Drawing.Point prtLU = GetWindowCornerLU(wndHandle);
    clientPoint.X += prtLU.X;
    clientPoint.Y += prtLU.Y;
    //System.Windows.Forms.MessageBox.Show("Click to " + clientPoint.X + " / " + clientPoint.Y + "");

    /// set cursor on coords, and press mouse
    System.Windows.Forms.Cursor.Position = new System.Drawing.Point(clientPoint.X, clientPoint.Y);

    INPUT inputMouseDown = new INPUT();
    inputMouseDown.Type = 0; /// input type mouse
    if(RightButton){
        inputMouseDown.Data.Mouse.Flags = MOUSEEVENTF_RIGHTDOWN; ///right button down
    }else{
        inputMouseDown.Data.Mouse.Flags = MOUSEEVENTF_LEFTDOWN; /// left button down
    }
    INPUT inputMouseUp = new INPUT();
    inputMouseUp.Type = 0; /// input type mouse
    if(RightButton){
        inputMouseUp.Data.Mouse.Flags = MOUSEEVENTF_RIGHTUP; /// right button up
    }else{
        inputMouseUp.Data.Mouse.Flags = MOUSEEVENTF_LEFTUP; /// left button up
    }

    var inputs = new INPUT[] { inputMouseDown, inputMouseUp };

    for(int i=0;i<nTimes;i++){
        SendInput((uint)inputs.Length, inputs, System.Runtime.InteropServices.Marshal.SizeOf(typeof(INPUT)));
    }

    /// return mouse 
    if(!KeepCursor){System.Windows.Forms.Cursor.Position = oldPos;}
}

}