Window drag event c# - c#

I am trying to hook into the window drag event of every active/visible windows using C# in a System tray app. I have the code to find and move all the windows figured out using PInvoke, but am unable to figure out how to hook into the drag event.
My goal is to run the program in the background and while dragging a window be able to snap it into preset locations (showing preview windows while the drag is occurring and snapping when released).
How would I hook into the window drag event?

You could try to set a CBT hook and handling the case when a window is about to be moved or sized, though this hook monitors much more than just this case:
class YourClassName
{
const int WH_CBT = 5;
private delegate IntPtr HookCallback(int nCode, IntPtr wParam, IntPtr lParam);
private IntPtr hHook;
private HookCallback hookCallback = new HookCallback(Callback);
[DllImport("user32")]
private static extern IntPtr SetWindowsHookEx(int idHook, HookCallback lpfn, IntPtr hMod, int dwThreadId);
[DllImport("user32")]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool UnhookWindowsHookEx(IntPtr hhk);
[DllImport("user32")]
private static extern IntPtr CallNextHookEx(IntPtr hhk, int nCode, IntPtr wParam, IntPtr lParam);
[DllImport("kernel32")]
private static extern IntPtr GetModuleHandle(string lpModuleName);
public void SetHook()
{
using (Process p = Process.GetCurrentProcess()
{
using (var mainMod = p.MainModule)
{
hHook = SetWindowsHookEx(WH_CBT, hookCallback, GetModuleHandle(mainMod.ModuleName, 0);
}
}
}
public bool Unhook()
{
return UnhookWindowsHookEx(hHook);
}
public IntPtr Callback(int nCode, IntPtr wParam, IntPtr lParam
{
if (nCode < 0)
return CallNextHookEx(hHook, nCode, wParam, lParam);
switch (nCode)
{
case 0:
// Handle window move/size here
// wParam is the handle of the window being moved or sized
// other cases...
}
return CallNextHookEx(hHook, nCode, wParam, lParam);
}
}
Don't forget to call Unhook() before terminating to free system resources.
For more information on SetWindowsHookEx see the msdn page.

Related

Working Global Mouse (and optionally Keyboard) Hook with .net core

I'm trying to detect the horizontal scroll wheel movement globally in .net core 3.1 (or at least movement of any mouse wheel). I want to build this application to work for both, Windows 10 x64 and arm-linux. However, I only need the hook functionality on Windows. I have tried to use the WindowsHook which includes System.Windows.Forms MouseEvents and also the normal MouseKeyHook which it is based on. Both didn't work. The same goes for my implementations of SetWindowsHookEx and the Raw Input API. Trying them in .net core applications only results in a massive input lag as soon as the listeners are in place and no events actually getting triggered. I searched for like two days now and I start to believe you need to be a wizard to get such a global hook to work in .net core. Help would be highly appreciated!
Edit: This is my first time working with hooks and doing low level stuff so I don't understand all of it 100%. I only have this code snippet here atm. For the WindowsHook and MouseKeyHook I just use the examples which you can find on corresponding linked github projects.
Here is the SetWindowsHookEx version, I just call the constructor to get it running and it doesn't even capture hscroll I believe:
using System;
using System.Runtime.InteropServices;
class Intercept_Mouse
{
private static LowLevelMouseProc _proc = HookCallback;
private delegate IntPtr LowLevelMouseProc(int nCode, IntPtr wParam, IntPtr lParam);
private static IntPtr _hookID = IntPtr.Zero;
public Intercept_Mouse()
{
_hookID = SetWindowsHookEx(WH_MOUSE_LL, _proc, IntPtr.Zero, 0);
}
private static IntPtr HookCallback(int nCode, IntPtr wParam, IntPtr lParam)
{
if (nCode >= 0 && (MouseMessages.WM_LBUTTONDOWN == (MouseMessages)wParam))
{
Console.WriteLine("Clicked");
}
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);
}

how to get multi touch event from SetWindowsHookEx in c#

I have found a way to separate touch and mouse events on wpf project. the issue I have now is that my hookProc() seems to be getting only the first touch events. when there are more than 2 touches on the screen, only the first touch has response from hookProc(). I want to be able to support multi touch in my application.
[DllImport("user32.dll")]
static extern IntPtr SetWindowsHookEx(int idHook, LowLevelMouseProc callback, IntPtr hInstance, uint threadId);
[DllImport("kernel32.dll")]
static extern IntPtr LoadLibrary(string lpFileName);
private delegate IntPtr LowLevelMouseProc (int nCode, IntPtr wParam, IntPtr lParam);
const int WH_MOUSE_LL = 14;
const uint MOUSEEVENTF_FROMTOUCH = 0xFF515700;
private LowLevelMouseProc _proc = hookProc;
private static IntPtr hhook = IntPtr.Zero;
public void SetHook()
{
IntPtr hInstance = LoadLibrary("User32");
hhook = SetWindowsHookEx(WH_MOUSE_LL, _proc, hInstance, 0);
}
public static IntPtr hookProc(int code, IntPtr wParam, IntPtr lParam)
{
MSLLHOOKSTRUCT info = (MSLLHOOKSTRUCT)Marshal.PtrToStructure(lParam, typeof(MSLLHOOKSTRUCT));
uint extraInfo = (uint)info.dwExtraInfo.ToInt32();
if ((extraInfo & MOUSEEVENTF_FROMTOUCH) == MOUSEEVENTF_FROMTOUCH)
{
System.Diagnostics.Debug.Print("this is touch");
}
else
{
System.Diagnostics.Debug.Print("this is mouse");
}
}
private void Form1_Load(object sender, RoutedEventArgs e)
{
SetHook();
}

Programatically Cancel Keyboard Command in C#

I'm trying to write a hook into MS Excel using VSTO's, and I'm really close to what I need, but I have a minor issue.
I've used the low-level WINAPI calls to get the Keyboard events and check for the key-strokes (which works well).
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern IntPtr SetWindowsHookEx(int idHook, KeyCaptureDelegate lpfn, IntPtr hMod, uint dwThreadId);
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern IntPtr CallNextHookEx(IntPtr hhk, int nCode, IntPtr wParam, IntPtr lParam);
private static IntPtr KeyCaptureCallback(int nCode, IntPtr wParam, IntPtr lParam)
{
if (nCode >= 0)
{
int pointerCode = Marshal.ReadInt32(lParam);
bool result = false;
if (wParam == (IntPtr)WM_KEYDOWN)
{
if (KeyDown != null)
{
result = KeyDown(pointerCode);
}
}
//if (result)
//return IntPtr.Zero;
}
return CallNextHookEx(_keyCaptureHook, nCode, wParam, lParam);
}
Everything is hooked up and working well (using SetWindowsHookEx) and my code gets called via KeyDown without any issues. The only problem is that I'm trying to override a default command in Excel, i.e. Ctrl+Shift+1. This causes the default functionality to occur.
In my code, result returns whether or not the behavior should be overwritten (i.e. use my new behavior, rather than default). I had hoped, perhaps, that returning IntPtr.Zero would break and remove the keys from the pump, but that seemed to not do anything.
Is there a way to block the other (default) behavior? I would imagine that by canceling/handling the event (like we can in WinForms/WPF), there should be some way to prevent the key stroke from migrating further into Excel. Any thoughts?
So, I needed to make a few minor changes:
private delegate IntPtr KeyCaptureDelegate(int nCode, IntPtr wParam, IntPtr lParam);
became:
private delegate int KeyCaptureDelegate(int nCode, IntPtr wParam, IntPtr lParam);
and
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern IntPtr CallNextHookEx(IntPtr hhk, int nCode, IntPtr wParam, IntPtr lParam);
became:
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern int CallNextHookEx(IntPtr hhk, int nCode, IntPtr wParam, IntPtr lParam);
Which allowed me to rewrite it as:
private static int KeyCaptureCallback(int nCode, IntPtr wParam, IntPtr lParam)
{
if (nCode >= 0)
{
int pointerCode = Marshal.ReadInt32(lParam);
bool result = false;
if (wParam == (IntPtr)WM_KEYDOWN)
{
if (KeyDown != null)
{
result = KeyDown(pointerCode);
}
}
if (result)
{
return 1;
}
}
return CallNextHookEx(_keyCaptureHook, nCode, wParam, lParam);
}

CoInternetSetFeatureEnabled with FEATURE_BLOCK_INPUT_PROMPTS does not work

I am trying to use CoInternetSetFeatureEnabled API for blocking prompt dialog as it show below in application that hosts WebBrowser control, but it does not work. Updating registry does not work either, following MSDN - Internet Feature Controls (I..L). I am using IE9 on Win7 64 bit.
FEATURE_BLOCK_INPUT_PROMPTS Internet Explorer 7. Enable or disable the
pop-up blocker to show input prompt dialog boxes. Used pop-up blocker
to mitigate the risk of spoofing.
private const int FEATURE_BLOCK_INPUT_PROMPTS = 27;
[DllImport("urlmon.dll")]
[PreserveSig]
[return: MarshalAs(UnmanagedType.Error)]
public static extern int CoInternetSetFeatureEnabled(
int FeatureEntry,
[MarshalAs(UnmanagedType.U4)] int dwFlags,
bool fEnable);
public static int disableInputPrompts(bool state)
{
return CoInternetSetFeatureEnabled(
FEATURE_BLOCK_INPUT_PROMPTS, SET_FEATURE_ON_PROCESS, state);
}
Update Just have tried in WinXP with IE8 and this feature is working. Does it depends on something else?
Update According to msdn this feature is by default enabled in IE9 but it does not work. Clicking on "Try It" button in w3schools sample initiates the prompt dialog, is that a security bug?
By default, this feature is enabled for Internet Explorer and disabled for
applications hosting the WebBrowser Control.
Any working alternative on how to block prompt dialog in WebBrowser control?
Can this be done by implementing custom security manager IInternetSecurityManager?
The only option I have for now is to use SetWindowsHookEx, and is based on Suppressing Hosted WebBrowser Control Dialogs sample.
internal static class WindowsInterop
{
private const Int32 WM_COMMAND = 0x0111;
private const Int32 WM_INITDIALOG = 0x0110;
private const Int32 WM_SYSCOMMAND = 0x0112;
private const Int32 SC_CLOSE = 0xF060;
private static IntPtr _pWH_CALLWNDPROCRET = IntPtr.Zero;
private static HookProcedureDelegate _WH_CALLWNDPROCRET_PROC =
new HookProcedureDelegate(WindowsInterop.WH_CALLWNDPROCRET_PROC);
[DllImport("user32.dll")]
private static extern IntPtr SetWindowsHookEx(Int32 hooktype,
HookProcedureDelegate callback, IntPtr hMod, UInt32 dwThreadId);
[DllImport("user32.dll")]
private static extern IntPtr UnhookWindowsHookEx(IntPtr hhk);
[DllImport("user32.dll")]
private static extern Int32 CallNextHookEx(IntPtr hhk, Int32 nCode,
IntPtr wParam, IntPtr lParam);
[DllImport("user32.dll")]
private static extern Int32 GetWindowTextLength(IntPtr hWnd);
[DllImport("user32.dll")]
private static extern Int32 GetWindowText(IntPtr hWnd,
StringBuilder text, Int32 maxLength);
[DllImport("user32.dll", SetLastError = false)]
private static extern IntPtr SendMessage(IntPtr hWnd, UInt32 Msg,
IntPtr wParam, IntPtr lParam);
// Hook Types
private const Int32 WH_CALLWNDPROCRET = 12;
[StructLayout(LayoutKind.Sequential)]
private struct CWPRETSTRUCT
{
public IntPtr lResult;
public IntPtr lParam;
public IntPtr wParam;
public UInt32 message;
public IntPtr hwnd;
};
// Delegate for a WH_ hook procedure
private delegate Int32 HookProcedureDelegate(Int32 iCode,
IntPtr pWParam, IntPtr pLParam);
// Delegate for the EnumChildWindows method
private delegate Boolean EnumerateWindowDelegate(IntPtr pHwnd, IntPtr pParam);
// Add a Hook into the CALLWNDPROCRET notification chain
internal static void Hook()
{
if (WindowsInterop._pWH_CALLWNDPROCRET == IntPtr.Zero)
{
WindowsInterop._pWH_CALLWNDPROCRET = SetWindowsHookEx(
WH_CALLWNDPROCRET,
WindowsInterop._WH_CALLWNDPROCRET_PROC,
IntPtr.Zero,
(uint)AppDomain.GetCurrentThreadId());
}
}
// Remove the Hook into the CALLWNDPROCRET notification chain
internal static void Unhook()
{
if (WindowsInterop._pWH_CALLWNDPROCRET != IntPtr.Zero)
{
UnhookWindowsHookEx(WindowsInterop._pWH_CALLWNDPROCRET);
}
}
// Hook proceedure called by the OS when a message has been processed by the target Window
private static Int32 WH_CALLWNDPROCRET_PROC(Int32 iCode,
IntPtr pWParam, IntPtr pLParam)
{
if (iCode < 0)
return CallNextHookEx(WindowsInterop._pWH_CALLWNDPROCRET,
iCode, pWParam, pLParam);
CWPRETSTRUCT cwp = (CWPRETSTRUCT)
Marshal.PtrToStructure(pLParam, typeof(CWPRETSTRUCT));
Console.WriteLine(cwp.message);
if (cwp.message == WM_INITDIALOG)
{
// A dialog was initialised, find out what sort it was via it's Caption text
Int32 iLength = GetWindowTextLength(cwp.hwnd);
StringBuilder sb = new StringBuilder(iLength + 1);
GetWindowText(cwp.hwnd, sb, sb.Capacity);
var title = sb.ToString();
if (String.IsNullOrEmpty(title) == false &&
title.IndexOf("prompt", StringComparison.OrdinalIgnoreCase) >= 0)
{
// just close it
SendMessage(cwp.hwnd, WM_SYSCOMMAND, new IntPtr(SC_CLOSE), IntPtr.Zero);
return 1;
}
}
// Call the next hook in the chain
return CallNextHookEx(WindowsInterop._pWH_CALLWNDPROCRET, iCode, pWParam, pLParam);
}
}

Low Level Keyboard Hooks installs automatically and slows down computer?

I am using Keyboard Low Level hooks in a desktop application to monitor user activity. Code i am using for hooks is give below.
In this code (upto my knowledge) when I have to start monitoring user activity I call SetHook() this will install hook and I can monitor keys pressed on keyboard. When I want to stop capturing keys i just call UnHook() method.
Problem is when my application starts (SetHook() method is not called yet) my application install hooks automatically and it slows down system. System hangs for for 2-3 seconds every 1 mint.
To diagnose the problem I commented out all the below mentioned code and installed application. Now system works absolutely fine.
I am not sure why is this happening?
Why my application start capturing keys even I did not called SetHook() method yet?
Is there is any other way to capture global keys without using hooks?
Code for Hooks:
public static class WinKeyCapture5 {
private const int WH_KEYBOARD_LL = 13;
private const int WM_KEYDOWN = 0x0100;
private static LowLevelKeyboardProc _proc = HookCallback;
public static DateTime LastKeyPressTime;
public static void SetHook()
{
SetHook(_proc);
}
public static void UnHook()
{
UnhookWindowsHookEx(_hookID);
}
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 static IntPtr _hookID = IntPtr.Zero;
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)
//{
int vkCode = Marshal.ReadInt32(lParam);
//if (vkCode == 44)
//ScreenCapture.Load();
LastKeyPressTime = System.DateTime.Now;
//}
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);
}

Categories