【问题标题】:SetWindowsHookEx fails with error 126SetWindowsHookEx 失败并出现错误 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},在我的项目中抛出异常也是如此!

【问题讨论】:

  • 可能与所涉及进程的位数有关...
  • 能否请您解释更多或指出正确的资源?
  • 挂钩通常涉及一些代码成为目标进程的一部分。这可以通过不同的方式实现,但基本上任何关于您的进程、挂钩进程和操作系统的位数差异都可能导致问题和/或错误行为。
  • 您能告诉我在这种情况下我该怎么办吗?有什么建议吗?
  • 对于这个特定的库,更改源代码可能会有所帮助(有关详细信息,请参阅stackoverflow.com/questions/2774741/module-not-found)。

标签: c# setwindowshookex


【解决方案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 版本上运行是目标。
  • 对不起,我错过了。非常感谢。
  • 非常感谢您发布此信息。我快要束手无策了……我正要卖掉我拥有的所有东西,然后搬到山上。
猜你喜欢
  • 2018-02-24
  • 2012-09-24
  • 2020-08-08
  • 1970-01-01
  • 2013-07-18
  • 2021-10-12
  • 2020-10-23
  • 2020-07-20
  • 2011-05-25
相关资源
最近更新 更多