2

I am trying to simulate mouse click without using mouse by sendmessage somehow it not working but there is no error show. here is my new code

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Runtime.InteropServices;
using System.Windows;
using System.Windows.Input;
using System.Diagnostics;


namespace WindowsFormsApplication1
{
    public partial class Form1 : Form
    {
        private const int BM_CLICK = 0x00F5;

        [DllImport("user32.dll", SetLastError = true)]
        static extern IntPtr FindWindow(string lpClassName, string lpWindowName);

        [DllImport("user32.dll", EntryPoint = "FindWindow", SetLastError = true)]
        static extern IntPtr FindWindowByCaption(IntPtr ZeroOnly, string lpWindowName);

        [DllImport("user32.dll", CharSet = CharSet.Auto)]
        static extern IntPtr SendMessage(IntPtr hWnd, UInt32 Msg, IntPtr wParam, IntPtr lParam);

        [DllImport("user32.dll", SetLastError = true)]
        public static extern IntPtr FindWindowEx(IntPtr parentHandle, IntPtr childAfter, string className, string windowTitle);

    public Form1()
    {
        InitializeComponent();
    }



        private void button1_Click(object sender, EventArgs e)
        {
            IntPtr hwndChild = IntPtr.Zero;
            IntPtr hwnd = IntPtr.Zero;
            hwnd = FindWindow(null, "MSPaintApp");
            hwndChild = FindWindowEx(hwnd, IntPtr.Zero, "Afx:00007FF765740000:8", null);
            SendMessage(hwndChild, BM_CLICK, IntPtr.Zero, IntPtr.Zero);
        }
    }
}

Can you someone show me how to put X Y coordination that it will click on a child window. I saw many post teaching how to do that but i can't know understand it and the system said do not ask question in other people question :(

newbie
  • 23
  • 1
  • 4

2 Answers2

4

To me the problem is that MSPaintApp window should be searched by using FindWindow("MSPaintApp", null) because MSPaintApp is the class name, not the window caption.

Then, Afx:00007FF765740000:8 is not child of MSPaintApp, but is child of MSPaintView that is child of MSPaintApp.

Also you don't have to "simulate" a BM_CLICK, but you have to simulate a WM_LBUTTONDOWN and then a WM_LBUTTONUP

Please consider this sample that seems to work (on Windows 7)

class Program
{
    private const uint WM_LBUTTONDOWN = 0x201;
    private const uint WM_LBUTTONUP = 0x202;
    private const uint MK_LBUTTON = 0x0001;

    public delegate bool EnumWindowsProc(IntPtr hWnd, IntPtr parameter);

    [DllImport("user32.dll", SetLastError = true)]
    static extern IntPtr FindWindow(string lpClassName, string lpWindowName);

    [DllImport("user32.dll", CharSet = CharSet.Auto)]
    static extern IntPtr SendMessage(IntPtr hWnd, UInt32 Msg, IntPtr wParam, IntPtr lParam);

    [DllImport("user32.dll", SetLastError = true)]
    public static extern IntPtr FindWindowEx(IntPtr parentHandle, IntPtr childAfter, string className, string windowTitle);

    [DllImport("user32.dll", SetLastError = true)]
    public static extern bool EnumChildWindows(IntPtr hwndParent, EnumWindowsProc lpEnumFunc, IntPtr lParam);

    static IntPtr childWindow;

    static void Main(string[] args)
    {                     
        IntPtr hwndMain = FindWindow("MSPaintApp", null);
        IntPtr hwndView = FindWindowEx(hwndMain, IntPtr.Zero, "MSPaintView", null);
        // Getting the child windows of MSPaintView because it seems that the class name of the child isn't constant
        EnumChildWindows(hwndView, new EnumWindowsProc(EnumWindow), IntPtr.Zero);
        // Simulate press of left mouse button on coordinates 10, 10
        SendMessage(childWindow, WM_LBUTTONDOWN, new IntPtr(MK_LBUTTON), CreateLParam(10, 10));
        // Simulate release of left mouse button on coordinates 100, 100
        SendMessage(childWindow, WM_LBUTTONUP, new IntPtr(MK_LBUTTON), CreateLParam(100, 100)); 
    }

    static bool EnumWindow(IntPtr handle, IntPtr pointer)
    {
        // Get the first child because it seems that MSPaintView has only this child
        childWindow = handle;
        // Stop enumerating the windows
        return false;
    }

    private static IntPtr CreateLParam(int LoWord, int HiWord)
    {
        return (IntPtr)((HiWord << 16) | (LoWord & 0xffff));
    }
}
Matteo Umili
  • 3,412
  • 1
  • 19
  • 31
  • Thank you a lot codroipo. You are my hero!!! I try it and it seem like it is working just as i hope. but this really leave me behind a big question. How can you know that hwndmain of paint is MsPaintApp. and the hwndView = MSPaintView? I mean maybe the next code i might be writing on difference program. How can i get the hwndmain and hwndview of the program correctly? – newbie Jan 12 '16 at 12:17
  • @EakzilaKung We know that `hwndMain` is `MSPaintApp` thanks to Spy++. The same for hwndView. If you want to write a generic method that simulates clicks over other program's windows I think that you can't, because programs use a lots of `Window`s. In Paint we know that to draw we have to click in the first child `window` of `MSPaintView`, other programs surely use another windows architecture(with different class names). For instance in Paint if we would want to click the `Paste` button we would need to find the appropriate window to send the appropriate message – Matteo Umili Jan 12 '16 at 12:59
  • That's really sound very complicated for me. after i read your message above. i try it with other program and it really have many child. And it look even more complicate is that the child i need to handle is child within child. and this//// IntPtr hwndView = FindWindowEx(hwndMain, IntPtr.Zero, "MSPaintView", null); why child after is IntPtr.Zero and String class name is MSPaintView. I thought MSPaintView is the childafter MsPaintApp. I am sorry... i not really know and i feel like i ask some stupid question. i try to look for answer by myself but not understand at all – newbie Jan 12 '16 at 14:53
  • @EakzilaKung Specifying childAfter to FindWindowEx means "ehy, FindWindowEx, enumerates all the child windows of `parent` that comes after `childAfter`" (for more info about the parameters look at [MSDN](https://msdn.microsoft.com/en-us/library/windows/desktop/ms633500%28v=vs.85%29.aspx)). `MSPaintView` is child of `MsPaintApp` and `Afx:000something` is child of `MSPaintView`. So the order is `MsPaintApp`->`MSPaintView`->`Afx:000something` – Matteo Umili Jan 12 '16 at 15:51
1

I'm going back many years here but I'm pretty sure mouse event window messages aren't delivered when applications are minimised. I'm sure a minimised window is treated differently anyway.

That aside, does this code work when the window is not minimised? You might want to use Spy++ to look at the structure of the window a little more as I think you will need to get the hWnd of whatever you're trying to click and send the message there. Very much depends on how the application itself was written and how the UI is drawn.

aaronrhodes
  • 615
  • 5
  • 10
  • well it not moving at all. don't matter Paint is minimize or not. i will also have a look at Spy++ and hWnd. Thank you – newbie Jan 08 '16 at 14:29
  • I've had a quick look and there seems to be a better way for emulating mouse input (presumably on the basis that you don't know which mouse events are being subscribed to and used in the target application). Have a look here: http://stackoverflow.com/questions/8021954/sendinput-doesnt-perform-click-mouse-button-unless-i-move-cursor – aaronrhodes Jan 08 '16 at 14:36