Search code examples
c#winapisetwindowshookex

SetWindowsHookEx seems not working for me in C# (WH_KEYBOARD_LL, global)


My application should perform some action whenever user pressed certain keys in windows.

Calling SetWindowsHookEx with WH_KEYBOARD_LL option seems to be standard way to achieve this. However in my case something is clearly wrong and callback in not fired.

Main method of my debugging console application:

static void Main(string[] args)
{
    IntPtr moduleHandle = GetCurrentModuleHandle();
    IntPtr hookHandle = IntPtr.Zero;

    try
    {
        User32.HookProc hook = (nCode, wParam, lParam) =>
        {
            // code is never called :-(
            if (nCode >= 0)
            {
                Console.WriteLine("{0}, {1}", wParam.ToInt32(), lParam.ToInt32());
            }
            return User32.CallNextHookEx(hookHandle, nCode, wParam, lParam);
        };

        hookHandle = User32.SetWindowsHookEx(User32.WH_KEYBOARD_LL, hook, moduleHandle, 0);

        Console.ReadLine(); // 
    }
    finally
    {
        if (hoodHandle != IntPtr.Zero)
        {
            var unhooked = User32.UnhookWindowsHookEx(hookHandle);
            Console.WriteLine(unhooked); // true
            hookHandle = IntPtr.Zero;                   
        }
    }
}

GetCurrentModuleHandle method:

private static IntPtr GetCurrentModuleHandle()
{
    using (var currentProcess = Process.GetCurrentProcess())
    using (var mainModule = currentProcess.MainModule)
    {
        var moduleName = mainModule.ModuleName;
        return Kernel32.GetModuleHandle(moduleName);
    }           
}

Imports from user32.dll and kernel32.dll:

public static class User32
{
    public const int WH_KEYBOARD_LL = 13;

    public delegate IntPtr HookProc(int nCode, IntPtr wParam, IntPtr lParam);

    [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
    public static extern IntPtr SetWindowsHookEx(int idHook, HookProc lpfn, IntPtr hMod, uint dwThreadId);

    [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
    [return: MarshalAs(UnmanagedType.Bool)]
    public static extern bool UnhookWindowsHookEx(IntPtr hhk);

    [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
    public static extern IntPtr CallNextHookEx(IntPtr hhk, int nCode, IntPtr wParam, IntPtr lParam);        
}

public static class Kernel32
{
    [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
    public static extern IntPtr GetModuleHandle(string lpModuleName);
}

Do you have any idea what I is my problem?


Solution

  • Is this a console app as Main(string[] args) and Console.ReadLine() would suggest?

    if so then this might be the source of your problem