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 :(
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));
}
}
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.
Related
I'm trying to Postmessage send key inputs to an application. The issue is that the message is being sent only when the application becomes active or gains focus.
Here is my goal:
I need the application to receive inputs either while it is not focused, or via some pseudo-focus called via postmessage before the input is sent (I have tried: NativeMethods.PostMessage(mainHwnd, 0x0007, 0, 0); "0x0007" is WM_SETFOCUS but this doesn't do anything). Any assistance would be very helpful, I've been at this for more hours than I care to count.🙏
Here is all of the relevant code I'm using:
using System.Runtime.InteropServices;
using System;
using System.Windows.Forms;
using System.Threading;
internal static class NativeMethods
{
[DllImport("user32.dll", SetLastError = true)]
public static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
[DllImport("user32.dll", SetLastError = true)]
public static extern IntPtr FindWindowEx(IntPtr hwndParent, IntPtr hwndChildAfter, string lpszClass, string lpszWindow);
[return: MarshalAs(UnmanagedType.Bool)]
[DllImport("user32.dll", SetLastError = true)]
public static extern bool PostMessage(IntPtr hWnd, UInt32 Msg, Int32 wParam, Int32 lParam);
[DllImport("User32.dll")]
public static extern int SendMessage(IntPtr hWnd, UInt32 uMsg, Int32 wParam, Int32 lParam);
}
class Test
{
const int WM_KEYDOWN = 0x0100;
const int WM_KEYUP = 0x0101;
//const int WM_SETFOCUS = 0x0007;
[DllImport("user32.dll")]
public static extern IntPtr SendMessage(IntPtr hWnd, UInt32 Msg, int wParam, int lParam);
public static void SendKey()
{
IntPtr mainHwnd = NativeMethods.FindWindow(null, "Test Application");
NativeMethods.PostMessage(mainHwnd, WM_KEYDOWN, (int)Keys.A, 0);
Thread.Sleep(50);
NativeMethods.PostMessage(mainHwnd, WM_KEYUP, (int)Keys.A, 0);
}
}
class TryTheThing{
public void Send() {
Test.SendKey();
}
}
Windows does not allow you to send keystrokes to non-focused applications. Your only option is to force the window to be focused first. This can be achieved by P/Invoking SetForegroundWindow():
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool SetForegroundWindow(IntPtr hWnd);
NativeMethods.SetForegroundWindow(mainHwnd);
I borrowed the following code I found online (the comments aren't even mine). When I click a button on my form, it waits and detects my next mouse click. Whatever I click on, it gets that information in the winHandle object inside the HookCallback method:
private static LowLevelMouseProc _proc = HookCallback;
private static IntPtr _hookID = IntPtr.Zero;
static IntPtr hHook = IntPtr.Zero;
private delegate IntPtr LowLevelMouseProc(int nCode, IntPtr wParam, IntPtr lParam);
private static IntPtr HookCallback(int nCode, IntPtr wParam, IntPtr lParam)
{
if (nCode >= 0 && MouseMessages.WM_LBUTTONDOWN == (MouseMessages)wParam)
{
// The application runs to here when you click on the window whose handle you want to get
POINT cusorPoint;
bool ret = GetCursorPos(out cusorPoint);
// cusorPoint contains your cusor’s position when you click on the window
// Then use cusorPoint to get the handle of the window you clicked
IntPtr winHandle = WindowFromPoint(cusorPoint);
// winHandle is the Hanle you need
// Now you have get the handle, do what you want here
// ………………………………………………….
Debug.WriteLine("Handle: " + winHandle.ToString());
// Because the hook may occupy much memory, so remember to uninstall the hook after
// you finish your work, and that is what the following code does.
UnhookWindowsHookEx(hHook);
hHook = IntPtr.Zero;
// Here I do not use the GetActiveWindow(). Let's call the window you clicked "DesWindow" and explain my reason.
// I think the hook intercepts the mouse click message before the mouse click message delivered to the DesWindow's
// message queue. The application came to this function before the DesWindow became the active window, so the handle
// abtained from calling GetActiveWindow() here is not the DesWindow's handle, I did some tests, and What I got is always
// the Form's handle, but not the DesWindow's handle. You can do some test too.
//IntPtr handle = GetActiveWindow();
}
return CallNextHookEx(_hookID, nCode, wParam, lParam);
}
private const int WH_MOUSE_LL = 14;
private enum MouseMessages
{
WM_LBUTTONDOWN = 0x0201,
WM_LBUTTONUP = 0x0202,
WM_MOUSEMOVE = 0x0200,
WM_MOUSEWHEEL = 0x020A,
WM_RBUTTONDOWN = 0x0204,
WM_RBUTTONUP = 0x0205
}
[StructLayout(LayoutKind.Sequential)]
private struct POINT
{
public int x;
public int y;
}
[StructLayout(LayoutKind.Sequential)]
private struct MSLLHOOKSTRUCT
{
public POINT pt;
public uint mouseData;
public uint flags;
public uint time;
public IntPtr dwExtraInfo;
}
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern IntPtr SetWindowsHookEx(int idHook,
LowLevelMouseProc lpfn, IntPtr hMod, uint dwThreadId);
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool UnhookWindowsHookEx(IntPtr hhk);
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern IntPtr CallNextHookEx(IntPtr hhk, int nCode,
IntPtr wParam, IntPtr lParam);
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern IntPtr GetModuleHandle(string lpModuleName);
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool GetCursorPos(out POINT lpPoint);
[DllImport("user32.dll")]
static extern IntPtr WindowFromPoint(POINT Point);
private void GetProcess_Click(object sender, EventArgs e)
{
if (IntPtr.Zero == hHook){
using (Process curProcess = Process.GetCurrentProcess())
using (ProcessModule curModule = curProcess.MainModule)
{
hHook = SetWindowsHookEx(WH_MOUSE_LL, _proc,
GetModuleHandle(curModule.ModuleName), 0);
}
}
}
The problem is I need to use the information from that object elsewhere in my code. But, since it doesn't return that information, I'm not sure how I could get access to it.
I don't think I can return it because it goes instead over to the CallNextHookEx method; I've tried putting it in its own class, but inside the HookCallBack method I don't have access to this. or datasets or anything else.
So what can I do to get that information from outside the static method HookCallback?
I'm trying to make a Unity3D Application that can control the volume of another application. So far I've gotten it to work to change the volume of ALL applications, but I'm having trouble to get it to change just one, e.g. Spotify. This is on Windows 8, but I'd like it to work for Windows 7 as well.
private const int APPCOMMAND_VOLUME_UP = 0xA0000;
private const int APPCOMMAND_VOLUME_DOWN = 0x90000;
private const int WM_APPCOMMAND = 0x319;
[DllImport("user32.dll")]
public static extern IntPtr SendMessage(IntPtr hWnd, int Msg, IntPtr wParam, IntPtr lParam);
[DllImport("user32.dll")]
public static extern IntPtr FindWindow(string strClassName, string strWindowName);
[DllImport("user32.dll", SetLastError = true)]
public static extern uint GetWindowThreadProcessId(IntPtr hWnd, out uint processId);
[DllImport("user32.dll")]
public static extern IntPtr GetActiveWindow();
public void DecreaseVolume()
{
IntPtr hWnd = FindWindow("SpotifyMainWindow", "Spotify");
if (hWnd == IntPtr.Zero)
return;
uint pID;
GetWindowThreadProcessId(hWnd, out pID);
Debug.Log(pID);
SendMessage(hWnd, WM_APPCOMMAND, hWnd, (IntPtr)APPCOMMAND_VOLUME_DOWN);
}
public void IncreaseVolume()
{
// same as above, but with APPCOMMAND_VOLUME_UP
}
I'm pretty sure I'm getting the correct handle (hWnd) from FindWindow() because the pID printed out matches the PID of Spotify in my Task Manager, however all this does is change the volume of everything instead of just Spotify. This is the same result as if I didn't specify a specific handle e.g.
SendMessage(IntPtr.Zero, WM_APPCOMMAND, IntPtr.Zero, (IntPtr)APPCOMMAND_VOLUME_DOWN);
or if I use GetActiveWindow().
I've never messed around with these windows api stuff until today, so any help would be very appreciated!
I want to create a program, which could make screenshot of scrolling window. As opposed to making screenshots, scrolling another app is difficult for me. Basing on a few scripts from web, I’ve written that:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Runtime.InteropServices;
using System.Diagnostics;
using System.Threading;
namespace scroller
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
[DllImport("user32.dll", CharSet = CharSet.Auto)]
public static extern int GetScrollPos(IntPtr hWnd, int nBar);
[DllImport("user32.dll")]
static extern int SetScrollPos(IntPtr hWnd, int nBar, int nPos, bool bRedraw);
[DllImport("user32.dll")]
static extern IntPtr SetParent(IntPtr hWndChild, IntPtr hWndNewParent);
[DllImport("user32.dll")]
static extern int SetWindowLong(IntPtr hWnd, int nIndex, int dwNewLong);
[DllImport("user32.dll", SetLastError = true)]
private static extern bool MoveWindow(IntPtr hwnd, int x, int y, int cx, int cy, bool repaint);
[DllImport("user32.dll")]
static extern IntPtr SetActiveWindow(IntPtr hWnd);
[DllImport("user32.dll", SetLastError = true)]
static extern void SwitchToThisWindow(IntPtr hWnd, bool fAltTab);
[DllImport("user32.dll", SetLastError = true)]
private static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
[DllImport("user32.dll", SetLastError = true)]
static extern IntPtr FindWindowEx(IntPtr hwndParent, IntPtr hwndChildAfter, string lpszClass, string lpszWindow);
[DllImport("User32.Dll", EntryPoint = "PostMessageA")]
static extern bool PostMessage(IntPtr hWnd, uint msg, int wParam, int lParam);
[DllImport("user32.dll")]
private static extern IntPtr GetForegroundWindow();
[DllImport("user32.dll")]
static extern int GetWindowText(IntPtr hWnd, StringBuilder text, int count);
internal delegate int WindowEnumProc(IntPtr hwnd, IntPtr lparam);
[DllImport("user32.dll")]
internal static extern bool EnumChildWindows(IntPtr hwnd, WindowEnumProc func, IntPtr lParam);
private void Form1_Load(object sender, EventArgs e)
{
List<IntPtr> result = new List<IntPtr>();
Thread.Sleep(5000);
IntPtr ParenthWnd = GetForegroundWindow();
if (!ParenthWnd.Equals(IntPtr.Zero))
{
StringBuilder myStringBuilder = new StringBuilder(256);
GetWindowText(ParenthWnd, myStringBuilder, 256);
this.Text = myStringBuilder.ToString();
IntPtr prevChild = IntPtr.Zero;
IntPtr currChild = IntPtr.Zero;
while (true)
{
currChild = FindWindowEx(ParenthWnd, prevChild, null, null);
if (currChild == IntPtr.Zero) break;
result.Add(currChild);
prevChild = currChild;
}
}
for(int i=0 ;i<=result.Count-1;i++){
IntPtr myHandle = result[i];
SetActiveWindow(ParenthWnd);
SwitchToThisWindow(myHandle, true);
SetScrollPos(myHandle, 0x1, 0, true);
PostMessage(myHandle, 0x115, 4 + 0x10000 * 0,0);
}
}
}
}
This waits 5 seconds, and moves scrollbars of all windows to top. It works e.g. with notepad, but not with web browsers, ms word and many others. What am I doing wrong?
i have a frustrating problem with registering global hook.
I am using this class in my windows application:
using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Windows.Forms;
class InterceptKeys
{
private const int WH_KEYBOARD_LL = 13;
private const int WM_KEYDOWN = 0x0100;
private static LowLevelKeyboardProc _proc = HookCallback;
private static IntPtr _hookID = IntPtr.Zero;
public static void Hook()
{
_hookID = SetHook(_proc);
}
private static IntPtr SetHook(LowLevelKeyboardProc proc)
{
using (Process curProcess = Process.GetCurrentProcess())
using (ProcessModule curModule = curProcess.MainModule)
{
return SetWindowsHookEx(WH_KEYBOARD_LL, proc,
GetModuleHandle(curModule.ModuleName), 0);
}
}
private delegate IntPtr LowLevelKeyboardProc(
int nCode, IntPtr wParam, IntPtr lParam);
private static IntPtr HookCallback(
int nCode, IntPtr wParam, IntPtr lParam)
{
if (nCode >= 0 && wParam == (IntPtr)WM_KEYDOWN)
{
MessageBox.Show("Test");
}
return CallNextHookEx(_hookID, nCode, wParam, lParam);
}
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern IntPtr SetWindowsHookEx(int idHook,
LowLevelKeyboardProc lpfn, IntPtr hMod, uint dwThreadId);
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool UnhookWindowsHookEx(IntPtr hhk);
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern IntPtr CallNextHookEx(IntPtr hhk, int nCode,
IntPtr wParam, IntPtr lParam);
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern IntPtr GetModuleHandle(string lpModuleName);
}
Here is Program.cs
namespace TestHooks
{
static class Program
{
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
InterceptKeys.Hook();
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new Form1());
}
}
}
Everything works (MessageBox pops up) but windows freezes for a moment and beeper beeps. The problem doesn't occur on Windows 7 just on Vista. Any suggestions please?
You cannot use MessageBox in your code. It blocks execution, the keyboard goes dead. Use Console.WriteLine() for example, output goes to the Visual Studio Output window.
Beware that this code won't work anymore on .NET 4.0, GetModuleHandle() will return NULL.