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.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.
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.