How do you perform mouse movements & clicks virtually [user32.dll] - c#

How do you perform mouse movements & clicks virtually ?
What I mean by virtually is that, the main mouse isn't affected, so basically "creating" a second mouse that is controlled by setting x/y position (pref with user32.dll).
I have read a few similar questions here but the answer usually is with your main mouse, Example:
DllImport("user32")]
public static extern int SetCursorPos(int x, int y);
^ this moves your main mouse to x&y position on screen, what I want is to perform this action with a "virtual mouse" so my main mouse isn't moved, so basically I can keep using my computer while this "virtual mouse" does something else in another window for example.
then using this "virtual mouse" to perform clicks [virtual key codes]
I have tried this:
IntPtr MakeLParam(int x, int y) => (IntPtr)((y << 16) | (x & 0xFFFF));
var pointPtr = MakeLParam(900, 1000);//x y cords
IntPtr hWnd = ScreenCapture.FindWindow(null, ScreenCapture.GetWindowName()); //Finds Window
PostMessage(hWnd, WM_MOUSEMOVE | WM_LBUTTONDOWN | WM_LBUTTONUP, IntPtr.Zero, pointPtr);
[DllImport("User32.dll")]
public static extern Int32 PostMessage(
IntPtr hWnd, // handle to destination window
int Msg, // message
IntPtr wParam, // first message parameter
IntPtr lParam); // second message parameter
But nothing happens at all, and my guess is that WM_MOUSEMOVE is not working properly
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;
public const int WM_MOUSEMOVE = 0x0200;
UPDATE, I think I solved it somewhat !
After reading more about PostMessage /SendInput, I found out that "application windows" can have layers of "application windows", so I used ispy++ to check it out, and yes the program had another layer where I wanted to click.
So to solve this I took the class name of the window where I wanted to click as well as the window name, here is an example code:
public static bool ClickTest()
{
IntPtr MakeLParam(int x, int y) => (IntPtr)((y << 16) | (x & 0xFFFF));//Just converts x&y to InPtr lParam
IntPtr WindowhWid = ScreenCapture.FindWindow(null, ScreenCapture.GetWindowName()); //Gets the window hWid
var ClasshWid = FindWindowEx(WindowhWid, IntPtr.Zero, "Classname", null); //Gets the Class hWid using WindowhWid AND the Class name (Need to find a way to get the classname using process list)
PostMessage(ClasshWid, WM_LBUTTONDOWN | WM_LBUTTONUP, 0, MakeLParam(938, 1011));//Finally sends it to the classhWid
return true;
}
Using these two functions
[DllImport("User32.dll")]
public static extern int FindWindowEx(
IntPtr hwndParent,
IntPtr hwndChildAfter,
string strClassName,
string strWindowName);
[DllImport("User32.dll")]
public static extern Int32 PostMessage(
int hWnd, // handle to destination window
int Msg, // message
int wParam, // first message parameter
IntPtr lParam); // second message parameter
Note that it won't click if the appilication window is MINIMIZED, although it will click if the window is behind another appilication window !
Also the X & Y is the screen X & Y and not the Application X & Y !
Now the question remains, why doesn't it work while the application window is minimized ?
The click doesn't go anywhere but to the application, so shouldn't it work while the application is minimized ?

It migiht not be what you're up to and what you look after, but AutoIT Dll offers plenty of automation ready to use and in the easiest way possible. Since you rely on a windows DLL then it's perfect.
If you're still on your own way to user32.dll then check Low level hook, that's what I used.
I highly recommend AutoIT dll though, it will save you ton of hair pulling hours guessing what's happening to the windows messages that do not respond properly

Related

Can you get the position of a window that is inside of another application

So I found an example from an answer provided here
There was an answer that gave this example of code to move the Notepad window to the top left corner of the screen. I tried it and it worked fine. I then tried it on a small project I am working on and I couldn't move it.
NOTE: I did change the "Notepad" to the name at the top of the window I wanted to move.
using System;
using System.Runtime.InteropServices; // For the P/Invoke signatures.
public static class PositionWindowDemo
{
// P/Invoke declarations.
[DllImport("user32.dll", SetLastError = true)]
static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
[DllImport("user32.dll", SetLastError = true)]
static extern bool SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, int X, int Y, int cx, int cy, uint uFlags);
const uint SWP_NOSIZE = 0x0001;
const uint SWP_NOZORDER = 0x0004;
public static void Main()
{
// Find (the first-in-Z-order) Notepad window.
IntPtr hWnd = FindWindow("Notepad", null);
// If found, position it.
if (hWnd != IntPtr.Zero)
{
// Move the window to (0,0) without changing its size or position
// in the Z order.
SetWindowPos(hWnd, IntPtr.Zero, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOZORDER);
}
}
}
I will give an example. Consider Visual Studios and how it has the Solution Explorer Window or the Output window, and I can drag them with the mouse and move them or undock them. Would there be a way to have an application that has windows inside of it similar to Visual Studios and get the position of them in a program?
I have seen many answers on here about moving a window or finding the active window etc. However I am not sure if I will be able to access this subWindow that is inside of another application.
Thanks

Handling AeroSnap message in WndProc

In my C# .NET 4 application, I use WndProc to process some messages mostly dealing with resizing the application to and from full screen.
Right now I am just handling SC_MAXIMIZE and WM_NCLBUTTONDBLCLK to determine if the window is being resized to or from a maximized state (I know I don't need WndProc to handle SC_MAXIMIZE, but Form_Resize didn't seem to fire for a WM_NCLBUTTONDBLCLK message when I double-click on the application's title bar.
Now I noticed that if I Aero Snap the window to the top of the screen to maximize it, neither of the above messages are posted so certain logic is not applied when the window is maximized via Aero Snap. I only want to handle the message if the window is snapped to the top of the screen rather than the right or left, or if a window is unsnappped from maximized position.
I couldn't find any of the window messages related to Aero Snap. Does anyone know of any references for those messages?
I'm guessing there aren't any special messages here; Aero is likely just using the plain Win32 APIs - ShowWindow(SW_MAXIMIZE) and similar.
The thing to uderstand with the SC_ messages are that those are requests from a menu asking the window to resize/restore/etc itself, but that is not the only mechanism for changing the windows's size. What's probably happening is that when a window gets SC_MAXIMIZE, the DefWndProc implements this by calling ShowWindow(SW_MAXIMIZE).
Your best best is to listen to the WM_SIZE message, which the window receives, regardless of what triggered the size change: system menu, API, or other means. In particular, the lParam will let you know if the window was maximized (SIZE_MAXIMIZED) or restored (SIZE_RESTORED).
Here is the code for handling WM_WINDOWPOSCHANGING message for Maximise instead of WM_SIZE message. Thanks to the 20 or more questions on SO that I had to read to find all the bits to put it together and get it working. This addresses the problems that I was having with multiple monitors using different resolutions.
//register the hook
public static void WindowInitialized(Window window)
{
IntPtr handle = (new WindowInteropHelper(window)).Handle;
var hwndSource = HwndSource.FromHwnd(handle);
if (hwndSource != null)
{
hwndSource.AddHook(WindowProc);
}
}
//the important bit
private static IntPtr WindowProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
{
switch (msg)
{
case 0x0046: //WINDOWPOSCHANGING
var winPos = (WINDOWPOS)Marshal.PtrToStructure(lParam, typeof(WINDOWPOS));
var monitorInfo = new MONITORINFO();
IntPtr monitorContainingApplication = MonitorFromWindow(hwnd, MonitorDefaultToNearest);
GetMonitorInfo(monitorContainingApplication, monitorInfo);
RECT rcWorkArea = monitorInfo.rcWork;
//check for a framechange - but ignore initial draw. x,y is top left of current monitor so must be a maximise
if (((winPos.flags & SWP_FRAMECHANGED) == SWP_FRAMECHANGED) && (winPos.flags & SWP_NOSIZE) != SWP_NOSIZE && winPos.x == rcWorkArea.left && winPos.y == rcWorkArea.top)
{
//set max size to the size of the *current* monitor
var width = Math.Abs(rcWorkArea.right - rcWorkArea.left);
var height = Math.Abs(rcWorkArea.bottom - rcWorkArea.top);
winPos.cx = width;
winPos.cy = height;
Marshal.StructureToPtr(winPos, lParam, true);
handled = true;
}
break;
}
return (IntPtr)0;
}
//all the helpers for dealing with this COM crap
[DllImport("user32")]
internal static extern bool GetMonitorInfo(IntPtr hMonitor, MONITORINFO lpmi);
[DllImport("user32")]
internal static extern IntPtr MonitorFromWindow(IntPtr handle, int flags);
private const int MonitorDefaultToNearest = 0x00000002;
[StructLayout(LayoutKind.Sequential)]
public struct WINDOWPOS
{
public IntPtr hwnd;
public IntPtr hwndInsertAfter;
public int x;
public int y;
public int cx;
public int cy;
public int flags;
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
public class MONITORINFO
{
public int cbSize = Marshal.SizeOf(typeof(MONITORINFO));
public RECT rcMonitor;
public RECT rcWork;
public int dwFlags;
}
[StructLayout(LayoutKind.Sequential, Pack = 0)]
public struct RECT
{
public int left;
public int top;
public int right;
public int bottom;
}

Refreshing system tray icons programmatically

I've an application which has a system tray icon. While uninstalling I'm killing the process if its running. So, as am not gracefully stopping the app, the icon remains in the system tray and will remove only if we hover the mouse on it. I wrote a code that would run the cursor along the tray and get the cursor back in its initial position. This is what I have done:
[DllImport("user32.dll")]
static extern IntPtr FindWindow(string className, string windowName);
[DllImport("user32.dll")]
static extern IntPtr FindWindowEx(IntPtr parent, IntPtr child, string className, string windowName);
[DllImport("user32.dll")]
static extern bool GetWindowRect(HandleRef handle, out RECT rct);
[StructLayout(LayoutKind.Sequential)]
struct RECT
{
public int Left;
public int Top;
public int Right;
public int Bottom;
}
void RefreshTray()
{
IntPtr taskbar_Handle = FindWindow("Shell_Traywnd", "");
IntPtr tray_Handle = FindWindowEx(taskbar_Handle, IntPtr.Zero, "TrayNotifyWnd", "");
RECT rct;
if (!(GetWindowRect(new HandleRef(null, tray_Handle), out rct)))
{
}
System.Drawing.Point init = Control.MousePosition;
for (int i = rct.Left; i < rct.Right-20; i++)
{
Cursor.Position = new System.Drawing.Point(i, (rct.Bottom + rct.Top) / 2);
}
Cursor.Position = init;
}
This works good in all the cases except when the option "do not show notification icons" is enabled. Is there some way I could refresh the tray in this case?
EDIT
As the comments suggested I changed my approach. Instead of killing the tray application, I established a communication between my application service (yeah, forgot to mention, I have a service too running along with the application) and tray application. While uninstalling, I stop the service, from the service stop method I would send a socket message of a particular format to the tray application and ask it to close and I would set the notify icon visibility to false. This would leave the Tray Application running in background so I am using "taskkill" to remove the application. It worked fine in Win7 and Vista, but is not working properly in Win XP. But I have not written any environment specific code. Any possible clue?
That's similar to what I use.
A simple floating Keyboard I added to a touch gallery interface. The user wanted to also have my keyboard as a standalone application on their desktop. So I did this, created a tray app for it. Now - what if its open and they launch my gallery?
They would have two keyboards.
Sure - the user could end the first - but its easier to just end it. There are no repercussions from me killing it, so I do. But the tray Icon remains, as its waiting for an event. To get around this, I refresh the Tray area.
Please note - This would only work on an English Locale Installation. To get this to work on another language, change "User Promoted Notification Area", and "Notification Area" to the translated / equivalent string.
[StructLayout(LayoutKind.Sequential)]
public struct RECT
{
public int left;
public int top;
public int right;
public int bottom;
}
[DllImport("user32.dll")]
public static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
[DllImport("user32.dll")]
public static extern IntPtr FindWindowEx(IntPtr hwndParent, IntPtr hwndChildAfter, string lpszClass,
string lpszWindow);
[DllImport("user32.dll")]
public static extern bool GetClientRect(IntPtr hWnd, out RECT lpRect);
[DllImport("user32.dll")]
public static extern IntPtr SendMessage(IntPtr hWnd, uint msg, int wParam, int lParam);
public static void RefreshTrayArea()
{
IntPtr systemTrayContainerHandle = FindWindow("Shell_TrayWnd", null);
IntPtr systemTrayHandle = FindWindowEx(systemTrayContainerHandle, IntPtr.Zero, "TrayNotifyWnd", null);
IntPtr sysPagerHandle = FindWindowEx(systemTrayHandle, IntPtr.Zero, "SysPager", null);
IntPtr notificationAreaHandle = FindWindowEx(sysPagerHandle, IntPtr.Zero, "ToolbarWindow32", "Notification Area");
if (notificationAreaHandle == IntPtr.Zero)
{
notificationAreaHandle = FindWindowEx(sysPagerHandle, IntPtr.Zero, "ToolbarWindow32",
"User Promoted Notification Area");
IntPtr notifyIconOverflowWindowHandle = FindWindow("NotifyIconOverflowWindow", null);
IntPtr overflowNotificationAreaHandle = FindWindowEx(notifyIconOverflowWindowHandle, IntPtr.Zero,
"ToolbarWindow32", "Overflow Notification Area");
RefreshTrayArea(overflowNotificationAreaHandle);
}
RefreshTrayArea(notificationAreaHandle);
}
private static void RefreshTrayArea(IntPtr windowHandle)
{
const uint wmMousemove = 0x0200;
RECT rect;
GetClientRect(windowHandle, out rect);
for (var x = 0; x < rect.right; x += 5)
for (var y = 0; y < rect.bottom; y += 5)
SendMessage(windowHandle, wmMousemove, 0, (y << 16) + x);
}
Shouldn't be difficult to close the current instance using something like pipes, or TCP if you don't feel like doing that and aren't running .NET4.0.
As everyone is implying, the issue is that by killing your process it doesn't get a chance to unregister its tray icon instance, so it sticks around until Windows attempts to send an event to it (the next time you move the mouse over it) at which point Windows will remove it.
Depending on what installer you are using, this could be quite easy or more difficult. Most popular installer frameworks allow for plugins, and a few of them support Pipes, many more support TCP requests. Alternatively, write up a small executable that your installer can run before it begins the uninstall process, which communicates with your primary app and sends a close message.
As a final note, if you can use .NET4.0 then I'd suggest looking at the built in System.IO.Pipes namespace and the included classes.
Use this tool
http://www.codeproject.com/Articles/19620/LP-TrayIconBuster
It iterates through ToolBarButtons in TrayNotifyWnd & NotifyIconOverflowWindow and removes those with null file names.
I found this (http://maruf-dotnetdeveloper.blogspot.com/2012/08/c-refreshing-system-tray-icon.html) solution worked for me.

Setting a Windows form to be bottommost

Some background
One of my current clients runs a chain of Internet points where customers an access the net through PC:s set up as "kiosks" (a custom-built application "locks" the computer until a user has signed in, and the running account is heavily restricted through the Windows group policy). Currently, each computer is running Windows XP and uses Active Desktop to display advertisements in the background. However, since my client has got problems with Active Desktop crashing on a daily basis (in addition to generally slowing down the computer) I have been asked to develop an application that replaces it.
The problem
I am trying to investigate whether it is possible to build a Windows forms application (using C#) that always stays in the background. The application should lie above the desktop (so that it covers any icons, files etc) but always behind all other running applications. I guess I'm really looking for a BottomMost property of the Form class (which doesn't exist, of course).
Any tips or pointers on how to achieve this would be highly appreciated.
This isn't directly supported by the .NET Form class, so you have two options:
1) Use the Win32 API SetWindowPos function.
pinvoke.net shows how to declare this for use in C#:
[DllImport("user32.dll")]
static extern bool SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, int X, int Y, int cx, int cy, uint uFlags);
static readonly IntPtr HWND_BOTTOM = new IntPtr(1);
const UInt32 SWP_NOSIZE = 0x0001;
const UInt32 SWP_NOMOVE = 0x0002;
const UInt32 SWP_NOACTIVATE = 0x0010;
So in your code, call:
SetWindowPos(Handle, HWND_BOTTOM, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
As you commented, this moves the form to the bottom of the z-order but doesn't keep it there. The only workaround I can see for this is to call SetWindowPos from the Form_Load and Form_Activate events. If your application is maximized and the user is unable to move or minimise the form then you might get away with this approach, but it's still something of a hack. Also the user might see a slight "flicker" if the form gets brought to the front of the z-order before the SetWindowPos call gets made.
2) subclass the form, override the WndProc function and intercept the WM_WINDOWPOSCHANGING Windows message, setting the SWP_NOZORDER flag (taken from this page).
I think the best way to do so is using the activated event handler and SendToBack method, like so:
private void Form1_Activated(object sender, EventArgs e)
{
this.SendToBack();
}
Set your window to be a child window of the desktop (the "Program Manager" or "progman" process). I've succeeded with this method in Windows XP (x86) and Windows Vista (x64).
I stumbled on this method while searching for a way to make a screensaver display as if it were wallpaper. It turns out, this is sort of built in to the system's .scr handler. You use screensaver.scr /p PID, where PID is the process id of another program to attach to. So write a program to find progman's handle, then invoke the .scr with that as the /p argument, and you have screensaver wallpaper!
The project I'm playing with now is desktop status display (shows the time, some tasks, mounted disks, etc), and it's built on Strawberry Perl and plain Win32 APIS (mainly the Win32::GUI and Win32::API modules), so the code is easy to port to or understand any dynamic language with similar Win32 API bindings or access to Windows' Scripting Host (eg, ActivePerl, Python, JScript, VBScript). Here's a relevant portion of the class that produces the window:
do { Win32::API->Import(#$_) or die "Win32::API can't import #$_ ($^E)" } for
[user32 => 'HWND FindWindow(LPCTSTR lpClassName, LPCTSTR lpWindowName)'],
[user32 => 'HWND SetParent(HWND hWndChild, HWND hWndNewParent)'],
sub __screen_x {
Win32::GUI::GetSystemMetrics(SM_CXSCREEN)
}
sub __screen_y {
Win32::GUI::GetSystemMetrics(SM_CYSCREEN)
}
sub _create_window { # create window that covers desktop
my $self = shift;
my $wnd = $$self{_wnd} = Win32::GUI::Window->new(
-width => __screen_x(), -left => 0,
-height => __screen_y(), -top => 0,
) or die "can't create window ($^E)";
$wnd->SetWindowLong(GWL_STYLE,
WS_VISIBLE
| WS_POPUP # popup: no caption or border
);
$wnd->SetWindowLong(GWL_EXSTYLE,
WS_EX_NOACTIVATE # noactivate: doesn't activate when clicked
| WS_EX_NOPARENTNOTIFY # noparentnotify: doesn't notify parent window when created or destroyed
| WS_EX_TOOLWINDOW # toolwindow: hide from taskbar
);
SetParent($$wnd{-handle}, # pin window to desktop (bottommost)
(FindWindow('Progman', 'Program Manager') or die "can't find desktop window ($^E)")
) or die "can't pin to desktop ($^E)";
Win32::GUI::DoEvents; # allow sizing and styling to take effect (otherwise DC bitmaps are the wrong size)
}
This program buffers output to prevent flickering, which you'll probably want to do as well. I create a DC (device context) and PaintDesktop to it (you could use any bitmap with only a couple more lines -- CreateCompatibleBitmap, read in a file, and select the bitmap's handle as a brush), then create a holding buffer to keep a clean copy of that background and a working buffer to assemble the pieces -- on each loop, copy in background, then draw lines and brush bitmaps and use TextOut -- which is then copied to the original DC, at which time it appears on screen.
Yes, function SetWindowPos with flag HWND_BOTTOM should help you. But, from my experience: even after calling SetWindowPos as result of some user operations your window may bring to front.
subclass the form, override the WndProc function and intercept the Windows message(s) that are responsible for moving it up the z-order when it gets activated.
Create a Panel that cover your form, but what ever you want on that Panel, then in the Panel's Click-Event write this.sendback .
I've managed to get rid of the flickering when using setwindowpos...
const UInt32 SWP_NOSIZE = 0x0001;
const UInt32 SWP_NOMOVE = 0x0002;
const UInt32 SWP_NOACTIVATE = 0x0010;
const UInt32 SWP_NOZORDER = 0x0004;
const int WM_ACTIVATEAPP = 0x001C;
const int WM_ACTIVATE = 0x0006;
const int WM_SETFOCUS = 0x0007;
static readonly IntPtr HWND_BOTTOM = new IntPtr(1);
const int WM_WINDOWPOSCHANGING = 0x0046;
[DllImport("user32.dll")]
static extern bool SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, int X,
int Y, int cx, int cy, uint uFlags);
[DllImport("user32.dll")]
static extern IntPtr DeferWindowPos(IntPtr hWinPosInfo, IntPtr hWnd,
IntPtr hWndInsertAfter, int x, int y, int cx, int cy, uint uFlags);
[DllImport("user32.dll")]
static extern IntPtr BeginDeferWindowPos(int nNumWindows);
[DllImport("user32.dll")]
static extern bool EndDeferWindowPos(IntPtr hWinPosInfo);
private void Window_Loaded(object sender, RoutedEventArgs e)
{
IntPtr hWnd = new WindowInteropHelper(this).Handle;
SetWindowPos(hWnd, HWND_BOTTOM, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE);
IntPtr windowHandle = (new WindowInteropHelper(this)).Handle;
HwndSource src = HwndSource.FromHwnd(windowHandle);
src.AddHook(new HwndSourceHook(WndProc));
}
private IntPtr WndProc(IntPtr hWnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
{
if (msg == WM_SETFOCUS)
{
IntPtr hWnd = new WindowInteropHelper(this).Handle;
SetWindowPos(hWnd, HWND_BOTTOM, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE);
handled = true;
}
return IntPtr.Zero;
}
private void Window_Closing(object sender, System.ComponentModel.CancelEventArgs e)
{
IntPtr windowHandle = (new WindowInteropHelper(this)).Handle;
HwndSource src = HwndSource.FromHwnd(windowHandle);
src.RemoveHook(new HwndSourceHook(this.WndProc));
}

Moving mouse cursor programmatically

To start out I found this code at http://swigartconsulting.blogs.com/tech_blender/2005/08/how_to_move_the.html:
public class Win32
{
[DllImport("User32.Dll")]
public static extern long SetCursorPos(int x, int y);
[DllImport("User32.Dll")]
public static extern bool ClientToScreen(IntPtr hWnd, ref POINT point);
[StructLayout(LayoutKind.Sequential)]
public struct POINT
{
public int x;
public int y;
}
}
Paste the following code in the button's click eventhandler:
Win32.POINT p = new Win32.POINT();
p.x = button1.Left + (button1.Width / 2);
p.y = button1.Top + (button1.Height / 2);
Win32.ClientToScreen(this.Handle, ref p);
Win32.SetCursorPos(p.x, p.y);
This will move the mouse pointer to the center of the button.
This code works great, but I can't seem to figure out how to extend it a bit. Let's say I have internet explorer (embedded in a windows form) open to a web page (some random page I don't know about before hand) with a drop down list box in it. I've modified the above code to move the cursor over and get the list box to drop down(using the mouse click method shown below to drop the list down), and also move up and down the list highlighting each item as the mouse pointer goes over, but for the life of me I cannot figure out how to actually make the mouse click on the currently selected item to keep the selection. The way I'm doing it now the drop down list box just closes and the selection isn't changed. I'm using the following code for the mouse click (which does get the list to drop down):
private static void MouseClick(int x, int y, IntPtr handle) //handle for the browser window
{
IntPtr lParam = (IntPtr)((y << 16) | x); // The coordinates
IntPtr wParam = IntPtr.Zero; // Additional parameters for the click (e.g. Ctrl)
const uint downCode = 0x201; // Left click down code
const uint upCode = 0x202; // Left click up code
SendMessage(handle, downCode, wParam, lParam); // Mouse button down
SendMessage(handle, upCode, wParam, lParam); // Mouse button up
}
I'm sure I'm missing something simple here, but for the life of me cannot figure out what it is. Thanks in advance everyone.
Bob
I believe that you're missing a correct WPARAM for the WM_LBUTTONDOWN message, which for the left-button is MK_LBUTTON
#define MK_LBUTTON 0x0001

Categories

Resources