Search code examples
c#winapisetwindowshookex

How to port the C++ SetWindowsHookEx to C# or is this not possible?


I was looking at the example in Microsoft KB318804 but they use the threadId of the "current" application!!! I have some C++ code which works but we have to rewrite it, and I would prefer to re-write in C# while I am in there. The one thing it does is get the threadId of the target application like so:

uint lastId = GetWindowThreadProcessId(targetHandle, IntPtr.Zero);

no, GetCurrentThread is not the correct call as I am getting the thread id of a remote application which is what we do today AND what we want to do. targetHandle is a handle to that remote application.

I cast this lastId to an int and tried to wire up C# code but the SetWindowsHookEx returns 0 and fails. Only AppDomain.GetCurrentThreadId() seems to work (even though it is deprecated, the replacement though doesn't work either).

Do I have to go with the C++ code then? or is there a way to get it to work in C#?

Currently we register the hookhandler in C++ with the other application and get events back.


Solution

  • Have you checked out the pinvoke.net entry for SetWindowsHookEx?

    If SetWindowsHookEx returns NULL, you are supposed to call GetLastError, so in C# you should call Marshal.GetLastWin32Error (Assuming that DllImportAttribute.SetLastError was included on the P/Invoke signature.)

    From pinvoke.net:

    Signature

    [DllImport("user32.dll", SetLastError = true)]
    static extern IntPtr SetWindowsHookEx(HookType hookType, HookProc lpfn, IntPtr hMod, uint dwThreadId);
    

    Calling

    IntPtr hHook;
    
    using (Process process = Process.GetCurrentProcess())
    using (ProcessModule module = process.MainModule)
    {
        IntPtr hModule = GetModuleHandle(module.ModuleName);
    
        hHook = SetWindowsHookEx(HookType.WH_KEYBOARD_LL, hook, hModule, 0);
    }
    

    Possibly related questions: