Main page | About | Articles | Previous Posts | Archives

Thursday, April 27, 2006

Creating a global keyboard hook in C# without unmanaged code

Since every article about making a global hook with .NET had an unmanaged .dll making the hook, I'll just write here how to make one without any custom hooker DLLs.

Note: .NET cannot make a global hook for other events than WH_KEYBOARD_LL or WH_MOUSE_LL

With some small changes (KBDLLHookStruct to IntPtr), this code can be used for other hooks too.

using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;

namespace WinHook {

public class KBHookEventArgs : EventArgs
public int HookCode;
public IntPtr wParam;
public KBDLLHookStruct lParam;

//Structure returned by a WH_KEYBOARD_LL hook
public struct KBDLLHookStruct
public int vkCode;
public int scanCode;
public int flags;
public int time;
public int dwExtraInfo;

//Hook Types
//more could be added
public enum HookType : int

Parts of this class stolen from MSDN and modified
public class GlobalKBHook {
//Callback for the hook
public delegate int KBHookProc(int code, IntPtr wParam, ref KBDLLHookStruct);

protected KBHookProc kbhook = null;
protected IntPtr hhook = IntPtr.Zero;

public delegate void KBHookEventHandler(object sender, KBHookEventArgs e);

public event KBHookEventHandler KBHookInvoked;

protected void OnKBHookInvoked(KBHookEventArgs e)
if(KBHookInvoked != null)
KBHookInvoked(this, e);

public GlobalKBHook()
kbhook = new KBHookProc(this.CoreKBHook);

public int CoreKBHook(int code, IntPtr wParam, ref KBDLLHookStruct lParam)
if (code < 0)
return CallNextHookEx(hhook, code, wParam, lParam);

KBHookEventArgs e = new KBHookEventArgs();
e.HookCode = code;
e.wParam = wParam;
e.lParam = lParam;

// Yield to the next hook in the chain
return CallNextHookEx(hhook, code, wParam, lParam);

public void Install()
int hInstance = LoadLibrary("User32");
hhook = SetWindowsHookEx(
(IntPtr)hInstance, //IntPtr.Zero for local hooks
0); //zero = global hook, otherwise use local thread ID

public void Uninstall()

//win32 api function for creating hooks
protected static extern IntPtr SetWindowsHookEx(HookType code,
HookProc func,
IntPtr hInstance,
int threadID);

//win32 api function for unhooking
protected static extern int UnhookWindowsHookEx(IntPtr hhook);

//win32 api function for continuing the hook chain
protected static extern int CallNextHookEx(IntPtr hhook,
int code,
IntPtr wParam,
KBDLLHookStruct lParam);

//Used to find HWND to user32.dll
public extern static int LoadLibrary(string lpLibFileName);

So uhh... that should be it... unless I forgot something. I have it a bit different in my app, so.. if you run into any probs with that and can't fix it.. just ask.

Basically to use that you'd do something like:

public partial class Form1 : Form
GlobalKBHook gkbh;

public Form1()
gkbh = new GlobalKBHook();
gkbh.KBHookInvoked += new GlobalKBHook.KBHookEventHandler(hookCallback);

private void hookCallback(object sender, KBHookEventArgs e)
//do something with the args here
//To get the key that was pressed,
//Keys key = (Keys)Enum.Parse(typeof(Keys),e.lParam.vkCode.ToString());

//if the key was pressed down, e.lParam.flags is 0, if the key was lifted, 128

Onwards, my loyal horde of wannabe-scriptkiddies who will presumably use this code to create their very own keyloggers!

and as a side note, I will probably post more frequently again after this small slow down... I'm again working on some intresting things.


  • Hi

    this portion of the class

    protected void OnKBHookInvoked(KBHookEventArgs e)

    causes a Inconsistent accessibility error? I have google and tried a few things but no luck any ideas????


    By Blogger psymon25, at 6:37 PM  

  • So, did you leave errors in the code to keep the script kiddies guessing? :)

    By Anonymous JebaDaHut, at 8:51 PM  

  • Well... I made this work... but your original code has all kinds of problems... you should fix it!

    By Anonymous Anonymous, at 7:30 AM  

  • i fixed it a bit till it worked, its good :), thx..

    By Blogger yuval, at 6:11 AM  

  • Great, thx.
    You could also use
    public static extern int ToAscii(int uVirtKey, int uScanCode, byte[] lpbKeyState, byte[] lpChar, int uFlags);

    to convert virtual keys to ASCII chars

    By Anonymous Anonymous, at 10:45 AM  

Post a Comment

<< Home