I am developing an application that needs to handle all messages sent by the OS to any application.
The code works fine for WH_KEYBOARD_LL only, but fails with WH_GETMESSAGE or WH_CALLWNDPROC
class Program
{
private const int WH_KEYBOARD_LL = 13;
private const int WH_GETMESSAGE = 3;
private const int WH_CALLWNDPROC = 4;
private const int WM_KEYDOWN = 0x0100;
private static HookProc _proc = new HookProc(HookCallback);
private static IntPtr _hookID = IntPtr.Zero;
static void Main(string[] args)
{
TextWriter tw = new StreamWriter("date.txt");
tw.Write(DateTime.Now);
tw.Close();
_hookID = SetHook(_proc);
Application.Run();
UnhookWindowsHookEx(_hookID);
}
private static IntPtr SetHook(HookProc proc)
{
using (Process curProcess = Process.GetCurrentProcess())
using (ProcessModule curModule = curProcess.MainModule)
{
return SetWindowsHookEx(WH_CALLWNDPROC , proc,
GetModuleHandle(curModule.ModuleName), 0);
}
}
private delegate IntPtr HookProc(int code, IntPtr wParam, IntPtr lParam);
private static IntPtr HookCallback(int code, IntPtr wParam, IntPtr lParam)
{
// This method is never called
return CallNextHookEx(_hookID, code, wParam, lParam);
}
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern IntPtr SetWindowsHookEx(int idHook,
HookProc 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);
}
}
Edit:
I think the problem is with the .NET Frame work
Global hooks are not supported in the .NET Framework
Except for the WH_KEYBOARD_LL low-level hook and the WH_MOUSE_LL low-level hook, you cannot implement global hooks in the Microsoft .NET Framework.
http://support.microsoft.com/kb/318804
why are you passing curModule.ModuleName into the winapi ?
According to http://support.microsoft.com/kb/318804, you can't do global hooks in .NET (except for WH_KEYBOARD_LL). See the information at the end of that article.
Related
While my C# WinForms app is running, I need to detect when the mouse pointer is moved over a 3rd party application.
I've done some Google'ing but I can't seem to find a useful code example that shows how to set up a Hook Procedure to another application using C# to detect Windows Messages.
Can someone please show me how to setup a C# hook procedure so I can detect the WM_MOUSEMOVE message on another app (e.g. Notepad.exe)?
Below is the C# Low Level Mouse Hook code I was looking for, from the blogs.msdn.com/b/toub/archive/2006/05/03/589468.aspx link (that David Heffernan posted)
class InterceptMouse
{
private static LowLevelMouseProc _proc = HookCallback;
private static IntPtr _hookID = IntPtr.Zero;
public static void Main()
{
_hookID = SetHook(_proc);
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)
{
if (nCode >= 0 &&
MouseMessages.WM_LBUTTONDOWN == (MouseMessages)wParam)
{
MSLLHOOKSTRUCT hookStruct = (MSLLHOOKSTRUCT)Marshal.PtrToStructure(lParam, typeof(MSLLHOOKSTRUCT));
Console.WriteLine(hookStruct.pt.x + ", " + hookStruct.pt.y);
}
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);
}
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);
}
I got this program:
https://learn.microsoft.com/en-us/archive/blogs/toub/low-level-keyboard-hook-in-c
using System;
using System.Diagnostics;
using System.Windows.Forms;
using System.Runtime.InteropServices;
namespace KeyboardInput
{
class InterceptKeys
{
private delegate IntPtr LowLevelKeyboardProc(int nCode, IntPtr wParam, IntPtr lParam);
private const int WH_KEYBOARD_LL = 13;
private const int WM_KEYDOWN = 0x0100;
private static LowLevelKeyboardProc _proc = HookCallback;
private static IntPtr _hookID = IntPtr.Zero;
static void Main(string[] args)
{
_hookID = SetHook(_proc);
Application.Run();
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 HookCallback(int nCode, IntPtr wParam, IntPtr lParam)
{
if (nCode >= 0 && wParam == (IntPtr)WM_KEYDOWN)
{
int vkCode = Marshal.ReadInt32(lParam);
Console.WriteLine((Keys)vkCode + " " + nCode + " " + wParam + " " + lParam);
}
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);
}
}
It captures keyboard input, but what I want is to be able to differentiate between two keyboards. I'd like to know if the key pressed was from the keyboard on my laptop or the keyboard that's connected via an USB.
How do I accomplish this?
To distinguish between input devices, you may probably need to use Raw Input API
Here is a detailed example
UPDATE: The above link seems to be down. But here is a similar question answered by the blogger who provided above example.
I found a way to capture the Print Screen button in C#. When pressing Alt + Print Screen a simple messagebox pops up saying the keys have been pressed. But it's unresponsive for a couple of seconds right after. I have no idea why this is happening.
Here's the code I use:
static class Program
{
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
_hookID = SetHook(_proc);
Application.Run(new Form1());
UnhookWindowsHookEx(_hookID);
}
/****************************************/
private const int WH_KEYBOARD_LL = 13;
//private const int WH_KEYBOARD_LL = 13;
private const int WM_KEYDOWN = 0x0100;
private const int VK_F1 = 0x70;
private static LowLevelKeyboardProc _proc = HookCallback;
private static IntPtr _hookID = IntPtr.Zero;
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)
{
Keys number = (Keys)Marshal.ReadInt32(lParam);
if (number == Keys.PrintScreen)
{
if ((wParam == (IntPtr)260 && Keys.Alt == Control.ModifierKeys && number == Keys.PrintScreen))
{
MessageBox.Show("You pressed alt+ print screen");
}
}
}
return CallNextHookEx(IntPtr.Zero, 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);
}
Does anyone have a clue why it's hanging after the messagebox?
Windows cannot dispatch the next keyboard message until the hook callback finished executing. Clearly you do not want to use MessageBox.Show(), that blocks the callback. Windows puts up with that for several seconds before it declares your code broken and disables the hook.
Use Debug.Print() instead.
I made a simple hook keyboard in C#, so i have this following code :
private static IntPtr hKeyboardHook = IntPtr.Zero;
private const int WH_KEYBOARD_LL = 13;
private const int WM_KEYDOWN = 0x100;
private delegate IntPtr LowLevelKeyboardProc(int nCode, IntPtr wParam, IntPtr 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, CallingConvention = CallingConvention.StdCall, SetLastError = true)]
private static extern int UnhookWindowsHookEx(IntPtr idHook);
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern IntPtr CallNextHookEx(IntPtr hhk, int nCode, IntPtr wParam, IntPtr lParam);
[DllImport("user32")]
private static extern int ToAscii(int uVirtKey, int uScanCode, byte[] lpbKeyState, byte[] lpwTransKey, int fuState);
[DllImport("user32")]
private static extern int GetKeyboardState(byte[] pbKeyState);
[DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
private static extern short GetKeyState(int vKey);
private delegate int HookProc(int nCode, int wParam, IntPtr lParam);
[DllImport("kernel32.dll")]
public static extern IntPtr GetModuleHandle(string lpModuleName);
private static LowLevelKeyboardProc _proc = HookCallback;
public void initialization()
{
using (Process curProcess = Process.GetCurrentProcess())
using (ProcessModule curModule = curProcess.MainModule)
{
hKeyboardHook = SetWindowsHookEx(WH_KEYBOARD_LL, _proc, GetModuleHandle(curModule.ModuleName), 0);
}
}
private static IntPtr HookCallback(int nCode, IntPtr wParam, IntPtr lParam)
{
if (nCode >= 0 && wParam == (IntPtr)WM_KEYDOWN)
{
int vkCode = Marshal.ReadInt32(lParam);
if (vkCode >= 32 && vkCode < 160)
Console.Write((Keys)vkCode);
if (vkCode == 13)
Console.WriteLine("\n");
}
return CallNextHookEx(hKeyboardHook, nCode, wParam, lParam);
}
It works fine with no problem !! my program grip all key pressed in other program and write it on the console.
But i want to have the name of the program where the key is pressed, and i don't know how i can do that.
Anyone can help me ?
You are using a low-level hook (WH_KEYBOARD_LL). Low-level hooks are dispatched before the window manager decides which program will receive the message. Therefore, there is no "name of the program where the key is pressed" because the window manager hasn't yet decided which program the keypress will be delivered to. (You can try to guess by calling GetForegroundWindow.)
(Just curious: What is the ultimate problem you're trying to solve by using a keyboard hook? Maybe there's a better way. I hope you're not writing a keylogger.)