C# 以编程方式在另一个窗口中单击鼠标

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/10355286/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-09 13:31:43  来源:igfitidea点击:

programmatically mouse click in another window

c#windowsclickmousemessage

提问by Dagob

Is it possible to click programmatically a location in another window without moving the mouse to that location and even if the window is not on-top? I want to send a kind of message to another window to simulate a mouse click on a location.

是否可以在不将鼠标移动到该位置的情况下以编程方式单击另一个窗口中的某个位置,即使该窗口不在顶部?我想向另一个窗口发送一种消息来模拟鼠标点击某个位置。

I tried to accomplish this with PostMessage:

我试图用 PostMessage 来完成这个:

PostMessage(WindowHandle, 0x201, IntPtr.Zero, CreateLParam(300,300));
PostMessage(WindowHandle, 0x202, IntPtr.Zero, CreateLParam(300,300));

I made the CreateLParam function this way:

我以这种方式创建了 CreateLParam 函数:

private static IntPtr CreateLParam(int LoWord, int HiWord)
{
     return (IntPtr)((HiWord << 16) | (LoWord & 0xffff));
}

The problem is that the window gets locked on his location. I think that my application clicks on the (1,1) coordinate. Can some on help me with this problem?

问题是窗口被锁定在他的位置上。我认为我的应用程序点击了 (1,1) 坐标。有人可以帮我解决这个问题吗?

Edit: This is PostMessage:

编辑:这是 PostMessage:

[return: MarshalAs(UnmanagedType.Bool)]
[DllImport("user32.dll")]
public static extern bool PostMessage(IntPtr WindowHandle, int Msg, IntPtr wParam, IntPtr lParam);

And 0x201 and 0x202 are WM_LBUTTONDOWN and WM_LBUTTONUP respectively.

而 0x201 和 0x202 分别是 WM_LBUTTONDOWN 和 WM_LBUTTONUP。

采纳答案by Antonio Bakula

You can't do that by sending messages, instead use SendInput Windows API.

你不能通过发送消息来做到这一点,而是使用 SendInput Windows API。

Call method ClickOnPoint, this is an example from form click event, so this.handleis form handle, note that these are client coordinates on window witch handle is send, you can easily change this and send screen coordinates, and in that case you don't need handle or ClientToScreen call below.

调用方法 ClickOnPoint,这是表单单击事件的一个示例,this.handle表单句柄也是如此,请注意,这些是发送窗口女巫句柄的客户端坐标,您可以轻松更改它并发送屏幕坐标,在这种情况下您不需要handle 或 ClientToScreen 调用如下。

ClickOnPoint(this.Handle, new Point(375, 340));

UPDATE: using SendInput now, tnx Tom.

更新:现在使用 SendInput,tnx Tom。

btw. I used only declarations needed for this sample, for anything more there is a nice library : Windows Input Simulator (C# SendInput Wrapper - Simulate Keyboard and Mouse)

顺便提一句。我只使用了此示例所需的声明,还有一个不错的库:Windows Input Simulator (C# SendInput Wrapper - Simulate Keyboard and Mouse)

  public class ClickOnPointTool
  {

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

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

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

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

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

#pragma warning restore 649


    public static void ClickOnPoint(IntPtr wndHandle , Point clientPoint)
    {
      var oldPos = Cursor.Position;

      /// get screen coordinates
      ClientToScreen(wndHandle, ref clientPoint);

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

      var inputMouseDown = new INPUT();
      inputMouseDown.Type = 0; /// input type mouse
      inputMouseDown.Data.Mouse.Flags = 0x0002; /// left button down

      var inputMouseUp = new INPUT();
      inputMouseUp.Type = 0; /// input type mouse
      inputMouseUp.Data.Mouse.Flags = 0x0004; /// left button up

      var inputs = new INPUT[] { inputMouseDown, inputMouseUp };
      SendInput((uint)inputs.Length, inputs, Marshal.SizeOf(typeof(INPUT)));

      /// return mouse 
      Cursor.Position = oldPos;
    }

  }

回答by ACE

I found in the past, a way to send message to Windows Media Playerso I used that to simulate click in application I wanted!

我过去发现了一种向Windows Media Player发送消息的方法, 所以我用它来模拟我想要的应用程序中的点击!

Using this class(code below) to find the window and to send messages you want!

使用这个类(下面的代码)来查找窗口并发送你想要的消息!

using System;
using System.Runtime.InteropServices;

namespace Mouse_Click_Simulator
{
    /// <summary>
    /// Summary description for Win32.
    /// </summary>
    public class Win32
    {
        // The WM_COMMAND message is sent when the user selects a command item from 
        // a menu, when a control sends a notification message to its parent window, 
        // or when an accelerator keystroke is translated.
        public const int WM_KEYDOWN = 0x100;
        public const int WM_KEYUP = 0x101;
        public const int WM_COMMAND = 0x111;
        public const int WM_LBUTTONDOWN = 0x201;
        public const int WM_LBUTTONUP = 0x202;
        public const int WM_LBUTTONDBLCLK = 0x203;
        public const int WM_RBUTTONDOWN = 0x204;
        public const int WM_RBUTTONUP = 0x205;
        public const int WM_RBUTTONDBLCLK = 0x206;

        // The FindWindow function retrieves a handle to the top-level window whose
        // class name and window name match the specified strings.
        // This function does not search child windows.
        // This function does not perform a case-sensitive search.
        [DllImport("User32.dll")]
        public static extern int FindWindow(string strClassName, string strWindowName);

        // The FindWindowEx function retrieves a handle to a window whose class name 
        // and window name match the specified strings.
        // The function searches child windows, beginning with the one following the
        // specified child window.
        // This function does not perform a case-sensitive search.
        [DllImport("User32.dll")]
        public static extern int FindWindowEx(
            int hwndParent, 
            int hwndChildAfter, 
            string strClassName, 
            string strWindowName);


        // The SendMessage function sends the specified message to a window or windows. 
        // It calls the window procedure for the specified window and does not return
        // until the window procedure has processed the message. 
        [DllImport("User32.dll")]
        public static extern Int32 SendMessage(
            int hWnd,               // handle to destination window
            int Msg,                // message
            int wParam,             // first message parameter
            [MarshalAs(UnmanagedType.LPStr)] string lParam); // second message parameter

        [DllImport("User32.dll")]
        public static extern Int32 SendMessage(
            int hWnd,               // handle to destination window
            int Msg,                // message
            int wParam,             // first message parameter
            int lParam);            // second message parameter
    }
}

For Example:

例如:

 Win32.SendMessage(iHandle, Win32.WM_LBUTTONDOWN, 0x00000001, 0x1E5025B);

Here's My Application Source Codethat I Created to auto click in "BlueStacks" Application in a specific interval!

是我创建的应用程序源代码,用于在特定时间间隔内自动单击“BlueStacks”应用程序!

For FindWindow, wParam, lParam, etc. you can feel free to ask me how to do it! it's not too hard :) ;) Hope it helped! :)

对于FindWindow, wParam,lParam等你可以随时问我怎么做!这不是太难:) ;) 希望它有所帮助!:)

回答by A.Stenyakin

I can't add a comment :D

我无法添加评论 :D

Work for me:

为我工作:

[DllImport("User32.dll")]
    public static extern Int32 SendMessage(
    int hWnd,               
    int Msg,                
    int wParam,            
    IntPtr lParam);

and combine coord in lParam like this:

并像这样在 lParam 中组合坐标:

private static IntPtr CreateLParam(int LoWord, int HiWord)
    {
        return (IntPtr)((HiWord << 16) | (LoWord & 0xffff));
    }

and use:

并使用:

Clicktoapp.SendMessage(0x00040156, Clicktoapp.WM_LBUTTONDOWN, 0x00000001, CreateLParam(150,150));
        Clicktoapp.SendMessage(0x00040156, Clicktoapp.WM_LBUTTONUP, 0x00000000, CreateLParam(150, 150));

0x00040156 - Window Handle.

0x00040156 - 窗口句柄。

I was looking for a window handle using spy ++ Each time it is new, so it's better to use FindWindow.

一直在找窗口句柄用spy ++每次都是新的,所以用FindWindow比较好。

P.S

聚苯乙烯

Screenshot of the application window even if the window is not on top

即使窗口不在顶部,应用程序窗口的屏幕截图

https://stackoverflow.com/a/911225/12928587

https://stackoverflow.com/a/911225/12928587

i use this solution. work great.

我使用这个解决方案。工作得很好。