I've been searching for a while and there are mostly results in C++ or other languages, and not C#. Things I've seen:
keybd_event() // A c++ method that theoretically can be included with a DLL import, but hasn't worked in testing
System.Windows.Forms.SendKeys.Send("{NUMLOCK}"}; // Forms namespace doesn't exist in Windows
Currently, I have code that executes every second or so to watch the state of numlock and update a graphic in my form accordingly. If a bool toggle is set, I also want it to force NumLock on:
internal partial class Interop
{
public static int VK_NUMLOCK = 0x90;
public static int VK_SCROLL = 0x91;
public static int VK_CAPITAL = 0x14;
public static int KEYEVENTF_EXTENDEDKEY = 0x0001; // If specified, the scan code was preceded by a prefix byte having the value 0xE0 (224).
public static int KEYEVENTF_KEYUP = 0x0002; // If specified, the key is being released. If not specified, the key is being depressed.
[DllImport("User32.dll", SetLastError = true)]
public static extern void keybd_event(
byte bVk,
byte bScan,
int dwFlags,
IntPtr dwExtraInfo);
[DllImport("User32.dll", SetLastError = true)]
public static extern short GetKeyState(int nVirtKey);
[DllImport("User32.dll", SetLastError = true)]
public static extern short GetAsyncKeyState(int vKey);
}
private void watcher(object source, ElapsedEventArgs e)
{
bool NumLock = (((ushort)GetKeyState(0x90)) & 0xffff) != 0;
if (!NumLock && fixers.watchNumL)
{
// Force NumLock back on
// Simulate a key press
Interop.keybd_event((byte)0x90,0x45,Interop.KEYEVENTF_EXTENDEDKEY | 0,IntPtr.Zero);
// Simulate a key release
Interop.keybd_event((byte)0x90,0x45,Interop.KEYEVENTF_EXTENDEDKEY | Interop.KEYEVENTF_KEYUP, IntPtr.Zero);
NumLock = (((ushort)GetKeyState(0x90)) & 0xffff) != 0;
}
if (NumLock)
{
this.Dispatcher.Invoke(() =>
{
fixerBoxes["NumL"].FixerImg.Source = new BitmapImage(new Uri(#"/graphics/num_lock_on.png", UriKind.Relative));
StatusBox.Text = "Num Lock ON";
});
}
else {
this.Dispatcher.Invoke(() =>
{
fixerBoxes["NumL"].FixerImg.Source = new BitmapImage(new Uri(#"/graphics/num_lock_off.png", UriKind.Relative));
StatusBox.Text = "Num Lock OFF";
});
}
}
public MainWindow()
{
// Start the watcher
System.Timers.Timer myTimer = new System.Timers.Timer();
// Tell the timer what to do when it elapses
myTimer.Elapsed += new ElapsedEventHandler(watcher);
// Set it to go off every second
myTimer.Interval = 1000;
// And start it
myTimer.Enabled = true;
}
Here is a class (with a library) that can do this for you. the library does much more, so it's maybe a bit overkill to use just for this. The approach uses the keybd_event function using pinvoke:
// Simulate a key press
Interop.keybd_event((byte)virtualKey,
0x45,
Interop.KEYEVENTF_EXTENDEDKEY | 0,
IntPtr.Zero);
// Simulate a key release
Interop.keybd_event((byte)virtualKey,
0x45,
Interop.KEYEVENTF_EXTENDEDKEY | Interop.KEYEVENTF_KEYUP,
IntPtr.Zero);
Pressing and releasing the button changes the state of the LED. virtualKey is one of the VK_ constants.
Here are the declarations:
internal partial class Interop
{
public static int VK_NUMLOCK = 0x90;
public static int VK_SCROLL = 0x91;
public static int VK_CAPITAL = 0x14;
public static int KEYEVENTF_EXTENDEDKEY = 0x0001; // If specified, the scan code was preceded by a prefix byte having the value 0xE0 (224).
public static int KEYEVENTF_KEYUP = 0x0002; // If specified, the key is being released. If not specified, the key is being depressed.
[DllImport("User32.dll", SetLastError = true)]
public static extern void keybd_event(
byte bVk,
byte bScan,
int dwFlags,
IntPtr dwExtraInfo);
[DllImport("User32.dll", SetLastError = true)]
public static extern short GetKeyState(int nVirtKey);
[DllImport("User32.dll", SetLastError = true)]
public static extern short GetAsyncKeyState(int vKey);
}
I've got an always on-top application (basically a status display) that I want to follow around another program and always sit just to the left of the minimize button.
I can get the Rect representing the "target" process using the following code which I can then pair with an offset to generate the initial position of my overlay.
Get the HWnd IntPtr:
private IntPtr HWnd = Process.GetProcessesByName("targetapplication")[0].MainWindowHandle;
Declare the function from user32.dll:
[DllImport("user32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool GetWindowRect(IntPtr hWnd, ref RECT lpRect);
And the appropriate struct:
[StructLayout(LayoutKind.Sequential)]
private struct RECT
{
public int Left;
public int Top;
public int Right;
public int Bottom;
}
And then call it on demand.
However, I would like to avoid constantly polling this value, so I would like to hook into the target application and respond whenever the target window is moved.
Looking around the user32.dll documentation, the only way I can see for doing this is using SetWindowsHookEx(). I'm not entirely sure of how I'd go about intercepting an event from here however.
I believe the target application is built off of WinForms but I cannot be sure. So solutions that let me respond to the target's Move event or directly to some Windows Message would both be useful.
Any ideas on how I can proceed?
A method to hook a Windows Form to another process (Notepad, in this case) and follow the movements of the process' Main Window, to create sort of a Toolbar that can interact with the process, using SetWinEventHook().
To get the hooked Window bounds, GetWindowRect() is not recommended. Better call DwmGetWindowAttribute() passing DWMWA_EXTENDED_FRAME_BOUNDS as the DWMWINDOWATTRIBUTE, which still returns a RECT. This because GetWindowRect() is not DpiAware and it may return a virtualized measure in some contexts, plus it includes the Window drop shadow in specific configurations.
Read more about DpiAwarenes, Screen layout and VirtualScreen here:
Using SetWindowPos with multiple monitors
Also refactored the Hook helper class and the NativeMethods declarations.
▶ To move to foreground the Tool Window, as in the animation, when the hooked Window becomes the Foreground Window, also hook the EVENT_SYSTEM_FOREGROUND event: you'll receive a notification when the Foreground Window changes, then compare with the handle of Window you're hooking.
A visual representation of the results:
The Form class initialization procedure:
using System.Diagnostics;
using System.Drawing;
using System.Linq;
using System.Runtime.InteropServices;
using System.Windows.Forms;
public partial class Form1 : Form
{
private IntPtr notepadhWnd;
private IntPtr hWinEventHook;
private Process targetProc = null;
protected Hook.WinEventDelegate WinEventDelegate;
static GCHandle GCSafetyHandle;
public Form1()
{
InitializeComponent();
WinEventDelegate = new Hook.WinEventDelegate(WinEventCallback);
GCSafetyHandle = GCHandle.Alloc(WinEventDelegate);
targetProc = Process.GetProcessesByName("notepad").FirstOrDefault(p => p != null);
try {
if (targetProc != null) {
notepadhWnd = targetProc.MainWindowHandle;
if (notepadhWnd != IntPtr.Zero) {
uint targetThreadId = Hook.GetWindowThread(notepadhWnd);
hWinEventHook = Hook.WinEventHookOne(
NativeMethods.SWEH_Events.EVENT_OBJECT_LOCATIONCHANGE,
WinEventDelegate, (uint)targetProc.Id, targetThreadId);
var rect = Hook.GetWindowRectangle(notepadhWnd);
// Of course, set the Form.StartPosition to Manual
Location = new Point(rect.Right, rect.Top);
}
}
}
catch (Exception ex) {
// Log and message or
throw;
}
}
protected void WinEventCallback(
IntPtr hWinEventHook,
NativeMethods.SWEH_Events eventType,
IntPtr hWnd,
NativeMethods.SWEH_ObjectId idObject,
long idChild, uint dwEventThread, uint dwmsEventTime)
{
if (hWnd == notepadhWnd &&
eventType == NativeMethods.SWEH_Events.EVENT_OBJECT_LOCATIONCHANGE &&
idObject == (NativeMethods.SWEH_ObjectId)NativeMethods.SWEH_CHILDID_SELF)
{
var rect = Hook.GetWindowRectangle(hWnd);
Location = new Point(rect.Right, rect.Top);
}
}
protected override void OnFormClosing(FormClosingEventArgs e)
{
base.OnFormClosing(e);
if (!e.Cancel) {
if (GCSafetyHandle.IsAllocated) GCSafetyHandle.Free();
Hook.WinEventUnhook(hWinEventHook);
}
}
protected override void OnShown(EventArgs e)
{
if (targetProc == null) {
this.Hide();
MessageBox.Show("Notepad not found!", "Target Missing", MessageBoxButtons.OK, MessageBoxIcon.Hand);
this.Close();
}
else {
Size = new Size(50, 140);
targetProc.Dispose();
}
base.OnShown(e);
}
The support classes used to reference the Windows API methods:
using System.Runtime.InteropServices;
using System.Security.Permissions;
public class Hook
{
public delegate void WinEventDelegate(
IntPtr hWinEventHook,
NativeMethods.SWEH_Events eventType,
IntPtr hwnd,
NativeMethods.SWEH_ObjectId idObject,
long idChild,
uint dwEventThread,
uint dwmsEventTime
);
public static IntPtr WinEventHookRange(
NativeMethods.SWEH_Events eventFrom, NativeMethods.SWEH_Events eventTo,
WinEventDelegate eventDelegate,
uint idProcess, uint idThread)
{
return NativeMethods.SetWinEventHook(
eventFrom, eventTo,
IntPtr.Zero, eventDelegate,
idProcess, idThread,
NativeMethods.WinEventHookInternalFlags);
}
public static IntPtr WinEventHookOne(
NativeMethods.SWEH_Events eventId,
WinEventDelegate eventDelegate,
uint idProcess,
uint idThread)
{
return NativeMethods.SetWinEventHook(
eventId, eventId,
IntPtr.Zero, eventDelegate,
idProcess, idThread,
NativeMethods.WinEventHookInternalFlags);
}
public static bool WinEventUnhook(IntPtr hWinEventHook) =>
NativeMethods.UnhookWinEvent(hWinEventHook);
public static uint GetWindowThread(IntPtr hWnd)
{
return NativeMethods.GetWindowThreadProcessId(hWnd, IntPtr.Zero);
}
public static NativeMethods.RECT GetWindowRectangle(IntPtr hWnd)
{
NativeMethods.DwmGetWindowAttribute(hWnd,
NativeMethods.DWMWINDOWATTRIBUTE.DWMWA_EXTENDED_FRAME_BOUNDS,
out NativeMethods.RECT rect, Marshal.SizeOf<NativeMethods.RECT>());
return rect;
}
}
public static class NativeMethods
{
[StructLayout(LayoutKind.Sequential)]
public struct RECT
{
public int Left;
public int Top;
public int Right;
public int Bottom;
public Rectangle ToRectangle() => Rectangle.FromLTRB(Left, Top, Right, Bottom);
}
public static long SWEH_CHILDID_SELF = 0;
//SetWinEventHook() flags
public enum SWEH_dwFlags : uint
{
WINEVENT_OUTOFCONTEXT = 0x0000, // Events are ASYNC
WINEVENT_SKIPOWNTHREAD = 0x0001, // Don't call back for events on installer's thread
WINEVENT_SKIPOWNPROCESS = 0x0002, // Don't call back for events on installer's process
WINEVENT_INCONTEXT = 0x0004 // Events are SYNC, this causes your dll to be injected into every process
}
//SetWinEventHook() events
public enum SWEH_Events : uint
{
EVENT_MIN = 0x00000001,
EVENT_MAX = 0x7FFFFFFF,
EVENT_SYSTEM_SOUND = 0x0001,
EVENT_SYSTEM_ALERT = 0x0002,
EVENT_SYSTEM_FOREGROUND = 0x0003,
EVENT_SYSTEM_MENUSTART = 0x0004,
EVENT_SYSTEM_MENUEND = 0x0005,
EVENT_SYSTEM_MENUPOPUPSTART = 0x0006,
EVENT_SYSTEM_MENUPOPUPEND = 0x0007,
EVENT_SYSTEM_CAPTURESTART = 0x0008,
EVENT_SYSTEM_CAPTUREEND = 0x0009,
EVENT_SYSTEM_MOVESIZESTART = 0x000A,
EVENT_SYSTEM_MOVESIZEEND = 0x000B,
EVENT_SYSTEM_CONTEXTHELPSTART = 0x000C,
EVENT_SYSTEM_CONTEXTHELPEND = 0x000D,
EVENT_SYSTEM_DRAGDROPSTART = 0x000E,
EVENT_SYSTEM_DRAGDROPEND = 0x000F,
EVENT_SYSTEM_DIALOGSTART = 0x0010,
EVENT_SYSTEM_DIALOGEND = 0x0011,
EVENT_SYSTEM_SCROLLINGSTART = 0x0012,
EVENT_SYSTEM_SCROLLINGEND = 0x0013,
EVENT_SYSTEM_SWITCHSTART = 0x0014,
EVENT_SYSTEM_SWITCHEND = 0x0015,
EVENT_SYSTEM_MINIMIZESTART = 0x0016,
EVENT_SYSTEM_MINIMIZEEND = 0x0017,
EVENT_SYSTEM_DESKTOPSWITCH = 0x0020,
EVENT_SYSTEM_END = 0x00FF,
EVENT_OEM_DEFINED_START = 0x0101,
EVENT_OEM_DEFINED_END = 0x01FF,
EVENT_UIA_EVENTID_START = 0x4E00,
EVENT_UIA_EVENTID_END = 0x4EFF,
EVENT_UIA_PROPID_START = 0x7500,
EVENT_UIA_PROPID_END = 0x75FF,
EVENT_CONSOLE_CARET = 0x4001,
EVENT_CONSOLE_UPDATE_REGION = 0x4002,
EVENT_CONSOLE_UPDATE_SIMPLE = 0x4003,
EVENT_CONSOLE_UPDATE_SCROLL = 0x4004,
EVENT_CONSOLE_LAYOUT = 0x4005,
EVENT_CONSOLE_START_APPLICATION = 0x4006,
EVENT_CONSOLE_END_APPLICATION = 0x4007,
EVENT_CONSOLE_END = 0x40FF,
EVENT_OBJECT_CREATE = 0x8000, // hwnd ID idChild is created item
EVENT_OBJECT_DESTROY = 0x8001, // hwnd ID idChild is destroyed item
EVENT_OBJECT_SHOW = 0x8002, // hwnd ID idChild is shown item
EVENT_OBJECT_HIDE = 0x8003, // hwnd ID idChild is hidden item
EVENT_OBJECT_REORDER = 0x8004, // hwnd ID idChild is parent of zordering children
EVENT_OBJECT_FOCUS = 0x8005, // hwnd ID idChild is focused item
EVENT_OBJECT_SELECTION = 0x8006, // hwnd ID idChild is selected item (if only one), or idChild is OBJID_WINDOW if complex
EVENT_OBJECT_SELECTIONADD = 0x8007, // hwnd ID idChild is item added
EVENT_OBJECT_SELECTIONREMOVE = 0x8008, // hwnd ID idChild is item removed
EVENT_OBJECT_SELECTIONWITHIN = 0x8009, // hwnd ID idChild is parent of changed selected items
EVENT_OBJECT_STATECHANGE = 0x800A, // hwnd ID idChild is item w/ state change
EVENT_OBJECT_LOCATIONCHANGE = 0x800B, // hwnd ID idChild is moved/sized item
EVENT_OBJECT_NAMECHANGE = 0x800C, // hwnd ID idChild is item w/ name change
EVENT_OBJECT_DESCRIPTIONCHANGE = 0x800D, // hwnd ID idChild is item w/ desc change
EVENT_OBJECT_VALUECHANGE = 0x800E, // hwnd ID idChild is item w/ value change
EVENT_OBJECT_PARENTCHANGE = 0x800F, // hwnd ID idChild is item w/ new parent
EVENT_OBJECT_HELPCHANGE = 0x8010, // hwnd ID idChild is item w/ help change
EVENT_OBJECT_DEFACTIONCHANGE = 0x8011, // hwnd ID idChild is item w/ def action change
EVENT_OBJECT_ACCELERATORCHANGE = 0x8012, // hwnd ID idChild is item w/ keybd accel change
EVENT_OBJECT_INVOKED = 0x8013, // hwnd ID idChild is item invoked
EVENT_OBJECT_TEXTSELECTIONCHANGED = 0x8014, // hwnd ID idChild is item w? test selection change
EVENT_OBJECT_CONTENTSCROLLED = 0x8015,
EVENT_SYSTEM_ARRANGMENTPREVIEW = 0x8016,
EVENT_OBJECT_END = 0x80FF,
EVENT_AIA_START = 0xA000,
EVENT_AIA_END = 0xAFFF
}
//SetWinEventHook() Object Ids
public enum SWEH_ObjectId : long
{
OBJID_WINDOW = 0x00000000,
OBJID_SYSMENU = 0xFFFFFFFF,
OBJID_TITLEBAR = 0xFFFFFFFE,
OBJID_MENU = 0xFFFFFFFD,
OBJID_CLIENT = 0xFFFFFFFC,
OBJID_VSCROLL = 0xFFFFFFFB,
OBJID_HSCROLL = 0xFFFFFFFA,
OBJID_SIZEGRIP = 0xFFFFFFF9,
OBJID_CARET = 0xFFFFFFF8,
OBJID_CURSOR = 0xFFFFFFF7,
OBJID_ALERT = 0xFFFFFFF6,
OBJID_SOUND = 0xFFFFFFF5,
OBJID_QUERYCLASSNAMEIDX = 0xFFFFFFF4,
OBJID_NATIVEOM = 0xFFFFFFF0
}
public enum DWMWINDOWATTRIBUTE : uint
{
DWMWA_NCRENDERING_ENABLED = 1, // [get] Is non-client rendering enabled/disabled
DWMWA_NCRENDERING_POLICY, // [set] DWMNCRENDERINGPOLICY - Non-client rendering policy - Enable or disable non-client rendering
DWMWA_TRANSITIONS_FORCEDISABLED, // [set] Potentially enable/forcibly disable transitions
DWMWA_ALLOW_NCPAINT, // [set] Allow contents rendered In the non-client area To be visible On the DWM-drawn frame.
DWMWA_CAPTION_BUTTON_BOUNDS, // [get] Bounds Of the caption button area In window-relative space.
DWMWA_NONCLIENT_RTL_LAYOUT, // [set] Is non-client content RTL mirrored
DWMWA_FORCE_ICONIC_REPRESENTATION, // [set] Force this window To display iconic thumbnails.
DWMWA_FLIP3D_POLICY, // [set] Designates how Flip3D will treat the window.
DWMWA_EXTENDED_FRAME_BOUNDS, // [get] Gets the extended frame bounds rectangle In screen space
DWMWA_HAS_ICONIC_BITMAP, // [set] Indicates an available bitmap When there Is no better thumbnail representation.
DWMWA_DISALLOW_PEEK, // [set] Don't invoke Peek on the window.
DWMWA_EXCLUDED_FROM_PEEK, // [set] LivePreview exclusion information
DWMWA_CLOAK, // [set] Cloak Or uncloak the window
DWMWA_CLOAKED, // [get] Gets the cloaked state Of the window. Returns a DWMCLOACKEDREASON object
DWMWA_FREEZE_REPRESENTATION, // [set] BOOL, Force this window To freeze the thumbnail without live update
PlaceHolder1,
PlaceHolder2,
PlaceHolder3,
DWMWA_ACCENTPOLICY = 19
}
public static SWEH_dwFlags WinEventHookInternalFlags =
SWEH_dwFlags.WINEVENT_OUTOFCONTEXT |
SWEH_dwFlags.WINEVENT_SKIPOWNPROCESS |
SWEH_dwFlags.WINEVENT_SKIPOWNTHREAD;
[DllImport("dwmapi.dll", SetLastError = true)]
internal static extern int DwmGetWindowAttribute(IntPtr hwnd, DWMWINDOWATTRIBUTE dwAttribute, out RECT pvAttribute, int cbAttribute);
[DllImport("user32.dll", SetLastError = true)]
internal static extern uint GetWindowThreadProcessId(IntPtr hWnd, out uint lpdwProcessId);
[DllImport("user32.dll")]
internal static extern uint GetWindowThreadProcessId(IntPtr hWnd, IntPtr voidProcessId);
[DllImport("user32.dll", SetLastError = false)]
internal static extern IntPtr SetWinEventHook(
SWEH_Events eventMin,
SWEH_Events eventMax,
IntPtr hmodWinEventProc,
Hook.WinEventDelegate lpfnWinEventProc,
uint idProcess, uint idThread,
SWEH_dwFlags dwFlags);
[DllImport("user32.dll", SetLastError = false)]
internal static extern bool UnhookWinEvent(IntPtr hWinEventHook);
}
Thanks to #Jimi for his help here. The following method worked.
First, store a reference to the target process:
Process _target = Process.GetProcessesByName("target")[0];
Then get the handle to the main window:
IntPtr _tagetHWnd = _target.MainWindowHandle;
Then initialise the hook:
SetWinEventHook(EVENT_OBJECT_LOCATIONCHANGE, EVENT_OBJECT_LOCATIONCHANGE, IntPtr.Zero, TargetMoved, (uint)_foxview.Id,
GetWindowThreadProcessId(_foxview.MainWindowHandle, IntPtr.Zero), WINEVENT_OUTOFCONTEXT | WINEVENT_SKIPOWNPROCESS | WINEVENT_SKIPOWNTHREAD);
Where SetWinEventHook is declared as such:
[DllImport("user32.dll")]
private static extern IntPtr SetWinEventHook(uint eventMin, uint eventMax, IntPtr hmodWinEventProc, WinEventDelegate lpfnWinEventProc, uint idProcess, uint idThread, uint dwFlags);
And the constants involved are:
private const uint EVENT_OBJECT_LOCATIONCHANGE = 0x800B;
private const int HT_CAPTION = 0x2;
private const uint WINEVENT_OUTOFCONTEXT = 0x0000;
private const uint WINEVENT_SKIPOWNPROCESS = 0x0002;
private const uint WINEVENT_SKIPOWNTHREAD = 0x0001;
private const int WM_NCLBUTTONDOWN = 0xA1;
Then in my TargetMoved method I get check the new Window location and move my overlay.
private void TargetMoved(IntPtr hWinEventHook, uint eventType, IntPtr lParam, int idObject, int idChild, uint dwEventThread, uint dwmsEventTime)
{
Rect newLocation = new Rect();
GetWindowRect(_foxViewHWnd, ref newLocation);
Location = new Point(newLocation.Right - (250 + _currentUser.Length * 7), newLocation.Top + 5);
}
Where GetWindowRect() is defined by:
[DllImport("user32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool GetWindowRect(IntPtr hWnd, ref Rect lpRect);
And Rect is defined by:
[StructLayout(LayoutKind.Sequential)]
private struct Rect
{
public readonly int Left;
public readonly int Top;
public readonly int Right;
public readonly int Bottom;
}
So when you put it all together, the entire class now looks like this:
using System;
using System.Diagnostics;
using System.Drawing;
using System.Runtime.InteropServices;
using System.Windows.Forms;
using UserMonitor;
namespace OnScreenOverlay
{
public partial class Overlay : Form
{
#region Public Fields
public const string UserCache = #"redacted";
#endregion Public Fields
#region Private Fields
private const uint EVENT_OBJECT_LOCATIONCHANGE = 0x800B;
private const uint WINEVENT_OUTOFCONTEXT = 0x0000;
private const uint WINEVENT_SKIPOWNPROCESS = 0x0002;
private const uint WINEVENT_SKIPOWNTHREAD = 0x0001;
private readonly Process _foxview;
private readonly IntPtr _foxViewHWnd;
private readonly UserMon _monitor;
private string _currentUser;
#endregion Private Fields
#region Public Constructors
public Overlay()
{
InitializeComponent();
_target= Process.GetProcessesByName("target")[0];
if (_foxview == null)
{
MessageBox.Show("No target detected... Closing");
Close();
}
_targetHWnd = _target.MainWindowHandle;
InitializeWinHook();
StartPosition = FormStartPosition.Manual;
Location = new Point(Screen.PrimaryScreen.Bounds.Left + 20, Screen.PrimaryScreen.Bounds.Bottom - 20);
ShowInTaskbar = false;
_monitor = new UserMon(UserCache);
_monitor.UserChanged += (s, a) =>
{
_currentUser = a.Value;
if (pictBox.InvokeRequired)
{
pictBox.Invoke((MethodInvoker)delegate { pictBox.Refresh(); });
}
};
_currentUser = _monitor.GetUser();
}
#endregion Public Constructors
#region Private Delegates
private delegate void WinEventDelegate(IntPtr hWinEventHook, uint eventType,
IntPtr hwnd, int idObject, int idChild, uint dwEventThread, uint dwmsEventTime);
#endregion Private Delegates
#region Private Methods
[DllImport("user32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool GetWindowRect(IntPtr hWnd, ref Rect lpRect);
[DllImport("user32.dll", SetLastError = true)]
private static extern uint GetWindowThreadProcessId(IntPtr hWnd, IntPtr processId);
[DllImport("user32.dll")]
private static extern IntPtr SetWinEventHook(uint eventMin, uint eventMax, IntPtr
hmodWinEventProc, WinEventDelegate lpfnWinEventProc, uint idProcess,
uint idThread, uint dwFlags);
private void InitializeWinHook()
{
SetWinEventHook(EVENT_OBJECT_LOCATIONCHANGE, EVENT_OBJECT_LOCATIONCHANGE, IntPtr.Zero, TargetMoved, (uint)_foxview.Id,
GetWindowThreadProcessId(_foxview.MainWindowHandle, IntPtr.Zero), WINEVENT_OUTOFCONTEXT | WINEVENT_SKIPOWNPROCESS | WINEVENT_SKIPOWNTHREAD);
}
private void Overlay_FormClosing(object sender, FormClosingEventArgs e)
{
_monitor.Dispose();
}
private void pictBox_Paint(object sender, PaintEventArgs e)
{
using (Font myFont = new Font("Arial", 8))
{
e.Graphics.DrawString($"User: {_currentUser}", myFont, Brushes.LimeGreen, new Point(2, 2));
}
}
private void TargetMoved(IntPtr hWinEventHook, uint eventType, IntPtr lParam, int idObject, int idChild, uint dwEventThread, uint dwmsEventTime)
{
Rect newLocation = new Rect();
GetWindowRect(_foxViewHWnd, ref newLocation);
Location = new Point(newLocation.Right - (250 + _currentUser.Length * 7), newLocation.Top + 5);
}
#endregion Private Methods
#region Private Structs
[StructLayout(LayoutKind.Sequential)]
private struct Rect
{
public readonly int Left;
public readonly int Top;
public readonly int Right;
public readonly int Bottom;
}
#endregion Private Structs
}
}
I'm trying to force a mouse click within my webbrowser at a specific point.
I'm using the following code:
public void DoMouseClick(int X, int Y)
{
//Call the imported function with the cursor's current position
mouse_event(MOUSEEVENTF_LEFTDOWN | MOUSEEVENTF_LEFTUP, X, Y, 0, 0);
}
[DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
public static extern void mouse_event(uint dwFlags, int dx, int dy, int cButtons, int dwExtraInfo);
private const int MOUSEEVENTF_LEFTDOWN = 0x02;
private const int MOUSEEVENTF_LEFTUP = 0x04;
private const int MOUSEEVENTF_RIGHTDOWN = 0x08;
private const int MOUSEEVENTF_RIGHTUP = 0x10;
However this code doesn't appear to be working at all, it isn't clicking there? I also am not sure whether this code actually moves the phsyical mouse or not, I need something that simulates a click not moves my mouse there and does the click.
I cannot use the HTMLElement stuff because that doesn't allow you to click a specific co-ordinate in the element, which I require, I need to click a very specific spot.
Could any one help with this
I got this, I used it for some auto-clicker stuff.. I can't and will not take any credit for this, I even think I found the code here on stackoverflow..
[Flags]
public enum MouseEventFlags
{
LeftDown = 0x00000002,
LeftUp = 0x00000004,
MiddleDown = 0x00000020,
MiddleUp = 0x00000040,
Move = 0x00000001,
Absolute = 0x00008000,
RightDown = 0x00000008,
RightUp = 0x00000010
}
[DllImport("user32.dll", EntryPoint = "SetCursorPos")]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool SetCursorPos(int X, int Y);
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool GetCursorPos(out MousePoint lpMousePoint);
[DllImport("user32.dll")]
private static extern void mouse_event(int dwFlags, int dx, int dy, int dwData, int dwExtraInfo);
public static void SetCursorPosition(int X, int Y)
{
SetCursorPos(X, Y);
}
public static void SetCursorPosition(MousePoint point)
{
SetCursorPos(point.X, point.Y);
}
public static MousePoint GetCursorPosition()
{
MousePoint currentMousePoint;
var gotPoint = GetCursorPos(out currentMousePoint);
if (!gotPoint) { currentMousePoint = new MousePoint(0, 0); }
return currentMousePoint;
}
public static void MouseEvent(MouseEventFlags value)
{
MousePoint position = GetCursorPosition();
mouse_event
((int)value,
position.X,
position.Y,
0,
0)
;
}
[StructLayout(LayoutKind.Sequential)]
public struct MousePoint
{
public int X;
public int Y;
public MousePoint(int x, int y)
{
X = x;
Y = y;
}
}
This question already has answers here:
Capturing mouse/keyboard events outside of form (app running in background)
(2 answers)
Closed 5 years ago.
I know how to modify cursor position from examples on MSDN.
My question is how to check position of mouse while mouse moves and then print X and Y position to representing labels?
EDIT: Lets say I want to track my mouse position from my entire screen.
EDIT 2: My app will be in the back ground/minimized.
I'm already using Mouse Hooks:
namespace Program
{
public partial class MouseHook
{
[DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
private static extern void mouse_event(int dwFlags, int dx, int dy, int dwData, IntPtr dwExtraInfo);
private const int MOUSEEVENTF_LEFTDOWN = 0x02;
private const int MOUSEEVENTF_LEFTUP = 0x04;
private const int MOUSEEVENTF_RIGHTDOWN = 0x08;
private const int MOUSEEVENTF_RIGHTUP = 0x10;
public void DoMouseClick()
{
int X = Cursor.Position.X;
int Y = Cursor.Position.Y;
IntPtr newP = new IntPtr(Convert.ToInt64("0", 16));
mouse_event(MOUSEEVENTF_LEFTDOWN | MOUSEEVENTF_LEFTUP, X, Y, 0, newP);
}
}
}
Here is the msdn documentation on system level mouse event handling calls (low level mouse proc).
Here is an example of using low level mouse procs to change the scroll event.
In the answer in the second link use WM_MOUSEMOVE from here instead of WM_MOUSEWHEEL.
One thing to note: for this program to continue to capture mouse events when the mouse is over a program with elevated privileges, this program will have to be launch with elevated privileges.
Code (not tested):
using System;
using System.Diagnostics;
using System.Windows.Forms;
using System.Runtime.InteropServices;
namespace CatchMouseMove
{
class InterceptMouse
{
const int INPUT_MOUSE = 0;
const int MOUSEEVENTF_WHEEL = 0x0800;
const int WH_MOUSE_LL = 14;
private static LowLevelMouseProc _proc = HookCallback;
private static IntPtr _hookID = IntPtr.Zero;
public static void Main()
{
_hookID = SetHook(_proc);
if (_hookID == null)
{
MessageBox.Show("SetWindowsHookEx Failed");
return;
}
Application.Run();
UnhookWindowsHookEx(_hookID);
}
private static IntPtr SetHook(LowLevelMouseProc proc)
{
using (Process curProcess = Process.GetCurrentProcess())
using (ProcessModule curModule = curProcess.MainModule)
{
return SetWindowsHookEx(WH_MOUSE_LL, proc,
GetModuleHandle(curModule.ModuleName), 0);
}
}
private delegate IntPtr LowLevelMouseProc(int nCode, IntPtr wParam, IntPtr lParam);
private static IntPtr HookCallback(int nCode, IntPtr wParam, IntPtr lParam)
{
int xPos = 0;
int yPos = 0;
if (nCode >= 0 && MouseMessages.WM_MOUSEMOVE == (MouseMessages)wParam)
{
xPos = GET_X_LPARAM(lParam);
yPos = GET_Y_LPARAM(lParam);
//do stuff with xPos and yPos
}
return CallNextHookEx(_hookID, nCode, wParam, lParam);
}
private enum MouseMessages
{
WM_MOUSEMOVE = 0x0200
}
[StructLayout(LayoutKind.Sequential)]
private struct POINT
{
public int x;
public int y;
}
[StructLayout(LayoutKind.Sequential)]
private struct MSLLHOOKSTRUCT
{
public POINT pt;
public int mouseData;
public int flags;
public int time;
public IntPtr dwExtraInfo;
}
public struct INPUT
{
public int type;
public MOUSEINPUT mi;
}
[StructLayout(LayoutKind.Sequential)]
public struct MOUSEINPUT
{
public int dx;
public int dy;
public int mouseData;
public uint dwFlags;
public int time;
public int 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);
}
}
You need to set a Windows hook in order to achieve this. The MSDN article How to set a Windows hook in Visual C# .NET shows how to set a mouse hook.
I tried it, it captures the mouse all over the form, even when the mouse cursor is over a control.
You can use the EventArgs of the MouseMove event, because it holds the mouse coordinates. From there you can easily set the text property of the label to the X or Y coordinate you will take from e (the MouseMove EventArgs).
private void Form_MouseMove(object sender, MouseEventArgs e)
{
// Update the mouse coordinates displayed in the textbox.
myTextBox.Text = e.Location.ToString();
}