6

I have a project that involves opening multiple window clients and then simulating mouse clicks within each of those processes. I've been able to succesfully send a message to multiple instances of Notepad using the Win32 API and SendMessage. The code that works for me is as follows:

Process[] notepads = Process.GetProcessesByName("notepad");
            foreach (Process proc in notepads)
            {
                    IntPtr handle = proc.Handle;
                    IntPtr child = FindWindowEx(proc.MainWindowHandle, new IntPtr(0), "Edit", null);
                    if (child != null)
                    {
                        MessageBox.Show("Child was found, sending text");
                        SendMessage(child, 0x000C, 0, "test");
                    }
                }
            }

This sends "test" to every instance I have opened of Notepad, no matter how many. As you can see I'm iterating through every instance of a process, and simply looping the message. Wasn't hard at all...

The end goal isn't Notepad, rather the Microsoft extension Awesomium. I retrieved the window handle, and then the child (Awesomium) Class name, which is Chrome_RenderWidgetHostHWND. From there, I tried to send mouse events by refactoring the variable types in Sendmessage in order to assemble and lParam readable by the system. Here is that code:

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

Using some examples I found I assemble the lParam via this:

int x = 834;
int y = 493;
IntPtr lParam = (IntPtr)((y << 16) | x);
IntPtr wParam = IntPtr.Zero;

I am using the Global Mouse hooks to detect press events in all child windows, and when I hit my button to iterate through the process and click, nothing is sent at all. I know I'm doing something stupid here that's causing the mouse clicks to not be sent. In any case, here is the final code structure that I have. Any advice, or tips would be appreciated. Thanks.

  private void button2_Click(object sender, EventArgs e)
    {
        Process[] notepads = Process.GetProcessesByName("client");
        foreach (Process proc in notepads)
        {
                IntPtr handle = proc.Handle;
                string mine = Convert.ToString(proc);
                MessageBox.Show(mine);
                IntPtr child = FindWindowEx(proc.MainWindowHandle, new IntPtr(0), "Chrome_RenderWidgetHostHWND", null);
                if (child != null)
                {
                int x = 834;
                int y = 493;
                IntPtr lParam = (IntPtr)((y << 16) | x);
                IntPtr wParam = IntPtr.Zero;
                SendMessage(child, 0x201, wParam, lParam);
                SendMessage(child, 0x202, wParam, lParam);
                }
            }
        }
  • Realizing several flaws with my code, I finally dug deep into WinInspector and retrieved all of the commands needed to initiate a mouse click. I'm such a noob. For anyone in the future, here are the messages needed in order to activate a click on Awesomium using Win32, most likely it's the same for all. WM_PARENTNOTIFY, WM_MOUSEACVTIVATE, WM_LBUTTONDOWN. The series of these three commands will notify the parent that the user has activated the mouse, then it performs a brief hittest, then finally depresses the left button. Hope this helps someone. – user2578424 Jul 19 '13 at 21:55
  • 3
    You should make an answer and then accept it. – Xcelled Jul 24 '13 at 19:56

1 Answers1

2

Or you could use SendInput instead, which will work correctly in the presence of mouse hooks; your solution (of posting messages directly) will not.

More importantly, if the process rejects activation (i.e., if the target returns 0 from WM_MOUSEACTIVATE), the WM_LBUTTONDOWN won't get sent.

Eric Brown
  • 13,774
  • 7
  • 30
  • 71