没有得到SetWindowsHookEx事件

本文关键字:SetWindowsHookEx 事件 | 更新日期: 2023-09-27 18:12:15

我有一个在生产中使用的KeyboardHook。伟大的工作。昨天我想做一个单元测试来测试我的一个想法,我做了一个抽象类,它有一个与HOOKPROC委托相匹配的虚拟方法。像这样……

public abstract class HookRuleBase : IDisposable
{
    private readonly IntPtr hookId;
    private static KeyboardProc thisDelegate;
    public HookRuleBase()
    {
        thisDelegate = new KeyboardProc(ProcessKey);
        IntPtr user = Kernel32.LoadLibrary("User32.dll");
        hookId = User32.SetWindowsHookEx(WH_KEYBOARD_LL, thisDelegate, user, 0);
        Console.WriteLine(hookId.ToInt32().ToString("X8"));
    }
    public void Dispose()
    {
        var disposed = User32.UnhookWindowsHookEx(hookId);
    }
    /// <summary>
    /// If your rule does not need to handle the key or the key's current state then call this base
    /// method.
    /// </summary>
    public virtual int ProcessKey(int code, System.UIntPtr wParam, ref KeyboardHookStruct lParam)
    {
        return User32.CallNextHookEx(hookId, code, wParam, ref lParam);
    }
    private const int WH_KEYBOARD_LL = 13;
}

我计划做的是替换一些静态方法,我在我的类称为KeyboardHook。我认为它遵循战略模式……我认为……Anywho。我创建了一个NUnit项目。创建了一个非常简单的类,扩展了我的HookRuleBase

    private class HookRuleTest : HookRuleBase
    {
        public override int ProcessKey(int code, UIntPtr wParam, ref KeyboardHookStruct lParam)
        {
            Console.WriteLine("ProcessKey:code:{0}, wParam:{1:X8}, {2}", code, wParam.ToUInt32(), lParam.ToString());
            return base.ProcessKey(code, wParam, ref lParam);
        }
    }

我在测试中尝试了一些东西。首先,我做了一个控制台哔哔声(我自己的音频),然后做了一个线程睡眠3秒…什么都没有。所以我偷了一些代码来测试我的一个虚拟键盘类。它只不过是一个在另一个线程中启动的Winforms表单。所以我放入了on load事件创建了钩子规则,在关闭时我处理了它。运行我的测试,输入hello world,在控制台中什么都没有:/所以作为最后的手段,我创建了一个新的winforms项目。复制加载和关闭事件的代码,将项目更改为控制台项目,然后运行我的代码。开始打字,果然我开始得到控制台窗口的输出。这让我很抓狂。我不知道为什么会这样。代码可以工作,但不是在Nunit中。有人能给我指指方向吗,为什么它不起作用。它的行为就像钩子正在接收任何事件,然而SetWindowsHookEx每次都返回一个有效的指针。所以我不知道。请帮助。

没有得到SetWindowsHookEx事件

您正在犯一个常见的错误,一个经常在低级钩子上犯的错误。Windows不能随意地对ProcessKey()方法进行回调。你的线程必须处于一种定义良好的状态,在这种状态下,Windows确信它是空闲的,并且进行调用可以是安全的,并且不会导致重入问题。

这种情况就是众所周知的"抽取消息循环"。消息循环是由。net程序中的Application.Run()启动的。启动它的线程不能被占用,它必须重新进入循环,等待Windows传递下一个消息。只有然后才能进行回调。

您没有从NUnit获得消息循环,它通过执行您的测试占用线程。你不会从"在另一个线程中启动的Winforms表单"中获得它,这是错误的线程。你从普通的Winforms项目中得到它,它的UI线程总是泵出一个消息循环,并且该线程花费99.9%的时间等待消息。

所以你看到的完全是设计出来的。您将找到提供这个答案的线程的示例代码。在Initialize()方法的重写中创建HookRuleTest对象

相关文章:
  • 没有找到相关文章