如何在托管代码中正确翻译WH_MOUSE参数

本文关键字:WH 翻译 MOUSE 参数 托管代码 | 更新日期: 2023-09-27 18:20:44

我已经设置了一个WH_MOUSE钩子,除了我无法将传递给我的HOOKPROC函数的lparam(指向 MOUSEHOOKSTRUCT 结构的指针(在 C# 中正确翻译之外,一切正常。

我的项目由两部分组成,C++中的非托管部分执行挂钩和筛选并通知我的托管代码。

问题是我得到不正确的数据,例如翻译lparam后奇怪的 X 和 Y 坐标。X 大部分时间是 0,而 Y 大部分时间是正确的,然后每隔一次点击我都会得到一个值,例如 X 的 198437245 和 Y 的 -1 等。

请注意,我已经确认了以下内容:

  • lparam 的值被正确地传递给我的 C# 代码(通过托管和非托管部件上的断点进行验证(,例如,当鼠标事件发生时,它们都是2420528的。
  • 非托管代码
  • 与托管代码位于同一上下文中,即相同的地址空间。
  • lparam 的值是正确的,因为我可以使用以下命令将其成功转换为非托管部分中的有效坐标:

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

    但是,在使用以下翻译后,X 和 Y 变得乱码。

这是我的C++ HOOKPROC函数:

static LRESULT CALLBACK InternalMouseHookCallback(int code, WPARAM wparam, LPARAM lparam)
{
    // filter messages
    // ...
    // send lparam to C# code
}

以下是我在 C# 中翻译lparam的方式:

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

以下是我将POINTMOUSEHOOKSTRUCT结构映射到 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;
}

我明显做错了什么?

更新

C++ 中的sizeof(MOUSEHOOKSTRUCT)和 C# 中的Marshal.SizeOf(typeof(MouseHookStruct))都打印20

我使用的是 Windows 7 64 位,但 C# 和 C++ 代码都是编译并以 32 位运行的。

如何在托管代码中正确翻译WH_MOUSE参数

public class POINT

POINT是原生winapi中的一个结构。 您倾向于在 C# 中将其声明为类。 但不是在以下情况下:

public class MouseHookStruct
{
    public POINT pt;
    // etc...
}

pt字段现在是引用,而不是值。 编组器将尝试取消引用 MOUSEHOOKSTRUCT.pt,就好像它是一个指针一样。 非常值得注意的是,这不会更频繁地产生巨大的爆炸声,顺便说一句,预计会出现访问违规异常。 也许您只在辅助显示器上测试过这个而倒霉。

您必须将其声明为struct

我发现,当执行流到达我的 C# 代码时,多次调用Marshal.ReadInt32(lparam)Marshal.ReadInt32(lparam, 4)读取XY值并没有返回相同的值。如果我阅读它的速度足够快,我会得到正确的结果,但在下一次迭代中不会。

这让我相信,当lparam到达我的 C# 代码并且我想处理它时,底层结构被释放了,lparam指向垃圾。

我不知道为什么我大部分时间都不幸地获得了正确的 Y 值,这真的让我很失望,让我怀疑结构映射不正确,也许是因为它的内存后来被填充了,而 X 的内存立即被其他东西填充。

我通过读取C++中的实际 MOUSEHOOKSTRUCT 字节并将它们发送到我的 C# 代码而不是发送lparam指针来解决我的问题。