Search code examples
c#c++winapihookmarshalling

How to Correctly Translate WH_MOUSE lparam in Managed Code


I've set up a WH_MOUSE hook, everything is working fine except that I can't get the lparam (pointer to a MOUSEHOOKSTRUCT structure) passed to my HOOKPROC function correctly translated in C#.

My project consists of two parts, an unmanaged part in C++ which does the hooking and filtering and notifying my managed code.

The problem is I get incorrect data e.g. weird X and Y coordinates after translating lparam. X is 0 most of the time, while Y is correct most of the time, then every other click I get a value like 198437245 for X and -1 for Y etc.

Please note that I have already confirmed the following:

  • lparam's value is correctly being passed to my C# code (verified via breakpoints on the managed and unmanaged parts), e.g. they are both 2420528 when a mouse event happens.
  • The unmanaged code is in the same context as the managed code i.e. same address space.
  • lparam's value is correct, because I can successfully translate it to valid coordinates in the unmanaged part using:

    POINT pt = reinterpret_cast<MOUSEHOOKSTRUCT*>(lparam)->pt;
    int x = pt.x; // correct, e.g. 250
    int y = pt.y; // correct, e.g. 400
    

    However, after using the below translation, X and Y become garbled.

Here's my C++ HOOKPROC function:

static LRESULT CALLBACK InternalMouseHookCallback(int code, WPARAM wparam, LPARAM lparam)
{
    // filter messages
    // ...

    // send lparam to C# code
}

Here's how I'm translating lparam in C#:

IntPtr lparam = ...; // passed from unmanaged code and confirmed to be the same value
MouseHookStruct mouseData =
    (MouseHookStruct)Marshal.PtrToStructure(lparam, typeof(MouseHookStruct));

Here's how I've mapped POINT and MOUSEHOOKSTRUCT structs to C#:

[StructLayout(LayoutKind.Sequential)]
public class POINT
{
    public int x;
    public int y;
}

[StructLayout(LayoutKind.Sequential)]
public class MouseHookStruct
{
    public POINT pt;
    public IntPtr hwnd;
    public uint wHitTestCode;
    public IntPtr dwExtraInfo;
}

What am I doing glaringly wrong?

UPDATE

sizeof(MOUSEHOOKSTRUCT) in C++ and Marshal.SizeOf(typeof(MouseHookStruct)) in C# both print 20.

I'm on Windows 7 64-bit but the C# and the C++ code are both compiled and running as 32-bit.


Solution

  • I found out that multiple calls to Marshal.ReadInt32(lparam) and Marshal.ReadInt32(lparam, 4) to read the X and Y values while the execution flow had reached my C# code did not return the same values. If I was reading it just fast enough, I would get correct results, but not on the next iterations.

    This led me to believe that by the time lparam reached my C# code and I wanted to process it, the underlying struct was freed and lparam was pointing to garbage.

    I'm not sure why I was unluckily getting correct Y values most of the time, which was really throwing me off and made me suspect that the struct mapping is incorrect, maybe because its memory was being filled in later, while X's memory was being filled instantly with something else.

    I've resolved my problem by reading the actual MOUSEHOOKSTRUCT bytes in C++ and sending them to my C# code rather than sending the lparam pointer.