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。 x64Any CPU 等其他选择适用于我的机器,但无论Platform target 如何,您的解决方案都适用,所以我将继续使用它,因为我的解决方案中有用 C++ 编写的 Win32 项目。您认为您的解决方案即使在 WindowsXP、Vista 或 Windows 8 等其他操作系统中也很可靠? 我在答案中明确指出,让它在任何 Windows 版本上运行是目标。 对不起,我错过了。非常感谢。 非常感谢您发布此信息。我快要束手无策了……我正要卖掉我拥有的所有东西,然后搬到山上。

以上是关于SetWindowsHookEx 失败并出现错误 126的主要内容,如果未能解决你的问题,请参考以下文章

SetWindowsHookEx 注入失败

WH_JOURNALRECORD 的 SetWindowsHookEx 在 Vista/Windows 7 下失败

调用外部 SetWindowsHookEx 和 GetModuleHandle 的 PInvoke 错误

FBSDKLoginManager 失败并出现错误代码 - 308

SetWindowsHookEx 不适用于线程 ID

AVAudioPlayer 失败并出现错误“无法完成操作。(OSStatus 错误 2003334207。)”