SetWindowsHookEx 失败并出现错误 126
Posted
技术标签:
【中文标题】SetWindowsHookEx 失败并出现错误 126【英文标题】:SetWindowsHookEx fails with error 126 【发布时间】:2013-07-27 12:09:01 【问题描述】:我正在尝试在一个项目中使用 Gma.UserActivityMonitor 库,但遇到了一个我自己无法克服的错误。
在HookManager.Callbacks.cs
文件中有一个名为EnsureSubscribedToGlobalMouseEvents
的静态方法,代码如下(或多或少):
var asm = Assembly.GetExecutingAssembly().GetModules()[0];
var mar = Marshal.GetHINSTANCE(asm);
s_MouseHookHandle = SetWindowsHookEx(
WH_MOUSE_LL,
s_MouseDelegate,
mar,
0);
//If SetWindowsHookEx fails.
if (s_MouseHookHandle == 0)
//Returns the error code returned by the last unmanaged function called using platform invoke that has the DllImportAttribute.SetLastError flag set.
int errorCode = Marshal.GetLastWin32Error();
//do cleanup
//Initializes and throws a new instance of the Win32Exception class with the specified error.
throw new Win32Exception(errorCode);
SetWindowsHookEx
总是返回 0
并且上面的代码不断抛出异常消息 The specified module could not be found
并且对 Marshal.GetLastWin32Error
的调用返回代码 126
。我可以成功运行 Gma.UserActivityMonitor 的原始项目提供的演示,但由于我的项目有点太复杂,无法在这里解释,我无法详细解释它与我的区别。我只是希望有人能盲猜这个问题。
顺便说一句,在项目的常见问题解答中,当仅在调试项目时检查 Enable Visual Studio hosting process
时,据说其他人遇到了与我接近的问题(SetWindowsHookEx
返回错误)。所以我取消选中了我的那个框,但我仍然遇到同样的问题,不仅在调试模式下,而且当我在 Windows 资源管理器中双击发布文件时(不涉及 Visual Studio)。
为了提供更多信息,在演示项目(工作正常)中,asm
变量指向Gma.UserActivityMonitor.dll
,在我的项目中抛出异常也是如此!
【问题讨论】:
可能与所涉及进程的位数有关... 能否请您解释更多或指出正确的资源? 挂钩通常涉及一些代码成为目标进程的一部分。这可以通过不同的方式实现,但基本上任何关于您的进程、挂钩进程和操作系统的位数差异都可能导致问题和/或错误行为。 您能告诉我在这种情况下我该怎么办吗?有什么建议吗? 对于这个特定的库,更改源代码可能会有所帮助(有关详细信息,请参阅***.com/questions/2774741/module-not-found)。 【参考方案1】:这种代码不再适用于 .NET 4 及更高版本。您得到的错误代码是描述性的,126 =“找不到指定的模块”。这告诉您“mar”变量包含垃圾。
.NET 4 对 CLR 进行了相当大的更改,它不再假装 jitted 代码存在于非托管模块中。所以 Marshal.GetHINSTANCE() 不再起作用了。然后代码变得草率,它忘记检查返回值,需要对其进行 (IntPtr)-1 测试以检测故障并宣布灾难。您在 Codeproject 中找到的代码很常见,有很多错误和草率,贡献者无法修复。不是 SO 模型:)
SetWindowsHookEx() 对于低级钩子来说有点尴尬。它需要一个有效的模块句柄,并检查它,但实际上并不使用它。这在 Windows 中得到了修复,在 Win7 SP1 附近的某个地方。虽然肯定打算成为一个有用的修复程序,但它实际上使问题变得更糟。因为现在它可以在您的开发机器上运行,但不能在您用户的机器上运行。
Anyhoo,修复很简单,您只需要提供一个有效的模块句柄即可。您可以从托管应用程序中始终存在的模块中获取一个,您需要通过pinvoke LoadLibrary 获取它:
var mar = LoadLibrary("user32.dll");
s_MouseHookHandle = SetWindowsHookEx(
WH_MOUSE_LL,
s_MouseDelegate,
mar,
0);
无需调用 FreeLibrary(),该模块会一直加载,直到您的程序终止为止。
【讨论】:
谢谢汉斯,它工作得很好。我只想补充一点,我设法找到了问题。你的将是我将使用的解决方案,但如果你愿意,我只是想问问你对我的新发现的看法。问题是我的项目的Platform target
设置为x86,而我的操作系统是Windows 7x64。 x64
和 Any CPU
等其他选择适用于我的机器,但无论Platform target
如何,您的解决方案都适用,所以我将继续使用它,因为我的解决方案中有用 C++ 编写的 Win32 项目。您认为您的解决方案即使在 WindowsXP、Vista 或 Windows 8 等其他操作系统中也很可靠?
我在答案中明确指出,让它在任何 Windows 版本上运行是目标。
对不起,我错过了。非常感谢。
非常感谢您发布此信息。我快要束手无策了……我正要卖掉我拥有的所有东西,然后搬到山上。以上是关于SetWindowsHookEx 失败并出现错误 126的主要内容,如果未能解决你的问题,请参考以下文章
WH_JOURNALRECORD 的 SetWindowsHookEx 在 Vista/Windows 7 下失败
调用外部 SetWindowsHookEx 和 GetModuleHandle 的 PInvoke 错误