How can I simulate a button click in the sendmessage API in C#?
C code:
#include <Windows.h>
//...
SendMessage(hWndButton, BM_CLICK, 0, 0);
C# code:
[DllImport("user32.dll")]
static extern IntPtr SendMessage(IntPtr hWnd, int msg, IntPtr wParam, IntPtr lParam);
...
Button myButton = ...;
const int BM_CLICK = 0x00F5;
SendMessage(myButton.Handle, BM_CLICK, IntPtr.Zero, IntPtr.Zero);
But be aware that, in C#, you can just as easily do:
myButton.PerformClick();
Related
More recently, simulating a click using PostMessage has begun to activate the window. Previously, this was not and the click was performed in an inactive window without focus.
int coords = (y << 16) + x;
IntPtr lParam = new IntPtr(coords);
PostMessage(hwnd, WM_LBUTTONDOWN, IntPtr.Zero, lParam);
PostMessage(hwnd, WM_LBUTTONUP, IntPtr.Zero, lParam);
[DllImport("user32.dll", SetLastError = true)]
static extern bool PostMessage(IntPtr hWnd, uint Msg, IntPtr wParam, IntPtr lParam);
const Int32 WM_LBUTTONDOWN = 0x201;
const Int32 WM_LBUTTONUP = 0x202;
i try to send Messages from one Application to another Application..
I think the Code works perfectly and is not the problem, but the text is sending to the wrong textbox? I looked with Spy++, and i have two textboxes in Application 2, but for both textboxes i return the same Class from Spy++ ---> "WindowsForms10.EDIT.app.0.141b42a_r13_ad1"...
My Main Question is now, why have both textboxes the same "class" and how can i fix this? thx
private const int WM_SETTEXT = 0x000C;
[DllImport("user32.dll")]
private static extern IntPtr FindWindow(string lpClassName,string lpWindowName);
[DllImport("User32.dll")]
private static extern IntPtr FindWindowEx(IntPtr hwndParent, IntPtr hwndChildAfter, string lpszClass, string lpszWindows);
[DllImport("User32.dll")]
private static extern Int32 SendMessage(IntPtr hWnd, int Msg, IntPtr wParam, StringBuilder lParam);
private void button4_Click(object sender, EventArgs e)
{
IntPtr hWnd = FindWindow(null, "Form1");
if (!hWnd.Equals(IntPtr.Zero))
{
IntPtr edithWnd = FindWindowEx(hWnd, IntPtr.Zero, "WindowsForms10.EDIT.app.0.141b42a_r13_ad1", null);
if (!edithWnd.Equals(IntPtr.Zero))
SendMessage(edithWnd, WM_SETTEXT, IntPtr.Zero, new StringBuilder("Hello World!"));
}
}
//Working Stuff...
IntPtr edithWnd = FindWindowEx(hWnd, IntPtr.Zero, "WindowsForms10.EDIT.app.0.141b42a_r12_ad1", null);
IntPtr nextHnd = edithWnd;
IntPtr editWnd = FindWindowEx(hWnd, nextHnd, "WindowsForms10.EDIT.app.0.141b42a_r12_ad1", null);
IntPtr nextHnd1 = editWnd;
IntPtr editWnd1 = FindWindowEx(hWnd, nextHnd1, "WindowsForms10.EDIT.app.0.141b42a_r12_ad1", null);
IntPtr nextHnd2 = editWnd1;
IntPtr editWnd2 = FindWindowEx(hWnd, nextHnd2, "WindowsForms10.EDIT.app.0.141b42a_r12_ad1", null);
Recently I tried to create a bot for an MMO-Game (called Florensia).
It should click on several positions in the game.
My problem is that it only sets the cursour to the position but the click doesn't work out. If I try it at my desktop or some other programs, it clicks correctly.
The game of course is in windowed mode and I already tried to set delays between the Mouseup and Mousedown.
Also to set the game to foreground window before the click didn't work.
Looking forward to any answers! :)
Try to use WinApi functions like in this example.
[DllImport("user32.dll")]
static extern IntPtr SendMessage(IntPtr hWnd, int msg, IntPtr wParam, IntPtr lParam);
[DllImport("user32.dll")]
static extern bool SetForegroundWindow(IntPtr hWnd);
static void Main(string[] args)
{
const int WM_LBUTTONDOWN = 0x0201;
const int WM_LBUTTONUP = 0x0202;
const int MK_LBUTTON = 0x0001;
uint x = 100;
uint y = 100;
IntPtr handle = new IntPtr(0x00090996); //Your window handle
SetForegroundWindow(handle);
Thread.Sleep(300);
SendMessage(handle, WM_LBUTTONDOWN, new IntPtr(MK_LBUTTON), new IntPtr(y << 16 | x));
Thread.Sleep(300);
SendMessage(handle, WM_LBUTTONUP, new IntPtr(0), new IntPtr(y << 16 | x));
}
I am trying to automate a dynamically appearing dialogue box.
I need to pass text to it,s text field and then press a button over this.
What I have tried so far.
[DllImport("user32.dll", EntryPoint = "FindWindow", SetLastError = true)]
static extern IntPtr FindWindowByCaption(IntPtr ZeroOnly, string lpWindowName);
IntPtr handle= FindWindowByCaption(System.IntPtr.Zero, "Caption Of File");
I am getting the handle of dialogue box correctly.
List<IntPtr> childWindows= GetChildWindows(handle);//To get the child controls in this dialogue box
Source
But when I try to cast it to control I get null.
foreach (IntPtr i in childWindows)
{
Control c = Control.FromHandle(i);
}
So can any body tell what is wrong.I am supposing that I shall cast handle to control and then interact with control properties(e.g: text).
I've been using code like this sucessfully for years to perform single sign on to an application that prompts the user for their username/pwd/domain. The only caution is you need to know the control structure of the dialog you're targeting, but this is easily accomplished with Spy++ and rarely changes. Of course you will need to modify this code for the control structure of your window.
[DllImport("user32.dll")]
static extern IntPtr FindWindowEx(IntPtr hwndParent, IntPtr hwndChildAfter,
string lpszClass, string lpszWindow);
[DllImport("user32.dll", CharSet = CharSet.Auto)]
public static extern IntPtr SendMessage(IntPtr hWnd, uint msg, int wParam, string lParam);
[DllImport("User32.Dll")]
public static extern IntPtr PostMessage(IntPtr hWnd, uint msg, int wParam, int lParam);
private const uint WM_GETTEXTLENGTH = 0x000E;
private const uint WM_SETTEXT = 0x000C;
private const uint WM_GETTEXT = 0x000D;
private const uint BM_CLICK = 0x00F5;
private const uint WM_CLOSE = 0x0010;
enum GetWindow_Cmd : uint
{
GW_HWNDFIRST = 0,
GW_HWNDLAST = 1,
GW_HWNDNEXT = 2,
GW_HWNDPREV = 3,
GW_OWNER = 4,
GW_CHILD = 5,
GW_ENABLEDPOPUP = 6
}
var dialog FindWindow("optionalClassNameHere", "Log On"); //Get the handle of the window
var w3 = GetWindow(dialog , (uint)GetWindow_Cmd.GW_CHILD); //I use GetWindow to walk the window controls
var wUid = FindWindowEx(w3, IntPtr.Zero, "Edit", "");
var w4 = GetWindow(wUid, (uint)GetWindow_Cmd.GW_HWNDNEXT);
var wPwd = FindWindowEx(w4 , IntPtr.Zero, "Edit", "");
var wOK = FindWindowEx(w3, IntPtr.Zero, "Button", "OK");
SendMessage(wUid, WM_SETTEXT, 0, _WinDomain + "\\" + Username); //Send username to username edit control
SendMessage(wPwd, WM_SETTEXT, 0, Password); //Send password to password edit control
PostMessage(wOK, BM_CLICK, 0, 0); //Send left click(0x00f5) to OK button
Control.FromHandle can only work for controls in your process that are implemented by Control descendents. I'd guess this window is outside your process.
You need to use Win32 API methods to modify it.
How might one invoke a callback whenever the current active window changes. I've seen how it might be done using CBTProc. However, global events aren't easy to hook into with managed code. I'm interested in finding a way that doesn't require polling. I'd prefer an event driven approach.
Regards
Create a new windows forms project, add a textbox, make it multiline, and set the textbox Dock property to fill, name it Log and paste in the following code (you'll need to add System.Runtime.InteropServices to your usings)...
WinEventDelegate dele = null;
public Form1()
{
InitializeComponent();
dele = new WinEventDelegate(WinEventProc);
IntPtr m_hhook = SetWinEventHook(EVENT_SYSTEM_FOREGROUND, EVENT_SYSTEM_FOREGROUND, IntPtr.Zero, dele, 0, 0, WINEVENT_OUTOFCONTEXT);
}
delegate void WinEventDelegate(IntPtr hWinEventHook, uint eventType, IntPtr hwnd, int idObject, int idChild, uint dwEventThread, uint dwmsEventTime);
[DllImport("user32.dll")]
static extern IntPtr SetWinEventHook(uint eventMin, uint eventMax, IntPtr hmodWinEventProc, WinEventDelegate lpfnWinEventProc, uint idProcess, uint idThread, uint dwFlags);
private const uint WINEVENT_OUTOFCONTEXT = 0;
private const uint EVENT_SYSTEM_FOREGROUND = 3;
[DllImport("user32.dll")]
static extern IntPtr GetForegroundWindow();
[DllImport("user32.dll")]
static extern int GetWindowText(IntPtr hWnd, StringBuilder text, int count);
private string GetActiveWindowTitle()
{
const int nChars = 256;
IntPtr handle = IntPtr.Zero;
StringBuilder Buff = new StringBuilder(nChars);
handle = GetForegroundWindow();
if (GetWindowText(handle, Buff, nChars) > 0)
{
return Buff.ToString();
}
return null;
}
public void WinEventProc(IntPtr hWinEventHook, uint eventType, IntPtr hwnd, int idObject, int idChild, uint dwEventThread, uint dwmsEventTime)
{
Log.Text += GetActiveWindowTitle() + "\r\n";
}
I know this thread is old, but for sake of future use:
when running the code you'll notice a crash after a while. This is caused from the line in the Form constructor:
public Form1()
{
InitializeComponent();
WinEventDelegate dele = new WinEventDelegate(WinEventProc);//<-causing ERROR
IntPtr m_hhook = SetWinEventHook(EVENT_SYSTEM_FOREGROUND, EVENT_SYSTEM_FOREGROUND, IntPtr.Zero, dele, 0, 0, WINEVENT_OUTOFCONTEXT);
}
Instead of the above make the following modification:
public Form1()
{
InitializeComponent();
dele = new WinEventDelegate(WinEventProc);
IntPtr m_hhook = SetWinEventHook(EVENT_SYSTEM_FOREGROUND, EVENT_SYSTEM_FOREGROUND, IntPtr.Zero, dele, 0, 0, WINEVENT_OUTOFCONTEXT);
}
WinEventDelegate dele = null;
..works now as expected!
You can use SetWinEventHook and listen for the EVENT_SYSTEM_FOREGROUND event. Use the WINEVENT_OUTOFCONTEXT flag to avoid the global-hook problem.