在Windows XP中使用SetWindowsHookEx时出现错误,但在Windows 7中没有。

5

我开发了一个应用程序,它使用全局键盘/鼠标钩子。在Windows 7中运行得很完美,但在Windows XP中却不行。

当我在Windows XP中调用SetWindowsHookEx时,会出现错误代码1428。

int MouseLowLevel   = 14
int code = SetWindowsHookEx(MouseLowLevel,
                 MouseHookProc,
                 IntPtr.Zero,
                 0);

private IntPtr MouseHookProc(int nCode, IntPtr wParam, IntPtr lParam) {}
1个回答

12

奇怪的是这段代码在Win7上不会失败,但我肯定从未尝试过。 但这是正确的行为,看起来他们进行了改进。 SetWindowsHookEx()的参数验证需要有效的非零第三或第四个参数。 错误代码非常描述性,来自WinError.h:

//
// MessageId: ERROR_HOOK_NEEDS_HMOD
//
// MessageText:
//
// Cannot set nonlocal hook without a module handle.
//
#define ERROR_HOOK_NEEDS_HMOD            1428L

由于在低级别挂钩中实际上不使用任何模块句柄,因此任何模块句柄都可以使用,而无需注入DLL即可使其工作。但是,在选择.NET 4的模块时需要小心,因为它的CLR不再为纯托管程序集伪造模块句柄。一个好的选择是使用从调用LoadLibrary("user32.dll")获得的模块句柄,因为它始终已经加载。你不必调用FreeLibrary()。

您需要这个声明来调用LoadLibrary:

[DllImport("kernel32", SetLastError=true, CharSet = CharSet.Auto)]
private static extern IntPtr LoadLibrary(string fileName);

非常感谢您的出色反应。现在它可以在Windows 7和XP上运行。 - magol
2
你的代码中又有一个bug,SetWindowsHookEx()的返回类型应该是IntPtr,而不是int。 - Hans Passant
哎呀,我在简化代码时犯了一些错误。在真正的代码中,我使用了一个继承自SafeHandleZeroOrMinusOneIsInvalid的类。但是当我附上代码时,我并不想过多涉及细节。 不过还是谢谢你 :-) - magol
2
我本以为GetModuleHandle("kernel32.dll")会是一个更明显的选择。 - David Heffernan
最小惊奇原则,SetWindowsHookEx需要一个使用user32.dll的pinvoke声明。 - Hans Passant

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接