1
public delegate void KeyboardHookCaptureHandler(KeyboardHookEventArgs keyboardEvents);

public class KeyboardHookEventArgs : EventArgs {

    private Keys _pressedKey;
    private int _pressedKeyCode;    

    public Keys PressedKey { get { return _pressedKey; } }
    public int PressedKeyCode { get { return _pressedKeyCode; } }

    public KeyboardHookEventArgs(int vkCode) {
        _pressedKey = (Keys)vkCode;
        _pressedKeyCode = vkCode;
    }
}

public class KeyboardHook {

    private delegate IntPtr LowLevelKeyboardProc(int nCode, IntPtr wParam, IntPtr lParam);

    public event KeyboardHookCaptureHandler KeyIntercepted;

    private const int WH_KEYBOARD_LL = 13;
    private const int WM_KEYDOWN = 0x0100;

    private LowLevelKeyboardProc _proc;
    private IntPtr _hookID = IntPtr.Zero;

    public KeyboardHook() {
        _proc = HookCallback;
        _hookID = SetHook(_proc);
    }
    public bool UnHookKey() {
        return UnhookWindowsHookEx(_hookID);
    }

    private IntPtr SetHook(LowLevelKeyboardProc proc) {
        using (Process curProcess = Process.GetCurrentProcess())
        using (ProcessModule curModule = curProcess.MainModule) {
            return SetWindowsHookEx(WH_KEYBOARD_LL, proc,
                GetModuleHandle(curModule.ModuleName), 0);
        }
    }

    private IntPtr HookCallback(
        int nCode, IntPtr wParam, IntPtr lParam) {
        if (nCode >= 0 && wParam == (IntPtr)WM_KEYDOWN) {
            int vkCode = Marshal.ReadInt32(lParam);          
            KeyboardHookEventArgs keyHookArgs = new KeyboardHookEventArgs(vkCode);
            KeyIntercepted(keyHookArgs);
        }
        return CallNextHookEx(_hookID, nCode, wParam, lParam);
    }


    [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
    private static extern IntPtr SetWindowsHookEx(int idHook,
        LowLevelKeyboardProc lpfn, IntPtr hMod, uint dwThreadId);

    [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
    [return: MarshalAs(UnmanagedType.Bool)]
    private static extern bool UnhookWindowsHookEx(IntPtr hhk);

    [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
    private static extern IntPtr CallNextHookEx(IntPtr hhk, int nCode,
        IntPtr wParam, IntPtr lParam);

    [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
    private static extern IntPtr GetModuleHandle(string lpModuleName);
}

所以我不知道这段代码是什么意思,即使它是我程序的核心。它挂钩一个键盘按下事件并将其发送到我的程序。任何人都可以花宝贵的时间向我解释一些事情。我了解 args 类,因此您可以跳过它。我最感兴趣的是什么是委托、什么是IntPtr以及这两种方法以及它们逐行执行的操作。

谢谢,如果有人有时间

4

3 回答 3

4

委托类型基本上指定了函数或方法的签名:它是将函数或方法捕获为对象的一种方式,以便您以后可以调用该方法。因此,委托实例基本上是对函数或方法的引用。

IntPtr是操作系统机指针——对一块非托管内存的不透明引用。

SetHook 方法是在 Windows 中安装一个钩子程序,以便系统中的每个键盘事件都会调用该钩子程序。什么是钩子程序?它是procLowLevelKeyboardProc委托类型的一个实例。在这种情况下,proc总是被设置为引用你的HookCallback函数。所以SetHook最终要做的是告诉 Windows 在每次键盘事件发生时调用 HookCallback

HookCallback 正在解压与键盘事件相关的本机操作系统信息,并使用解压后的数据引发 KeyIntercepted 事件。然后它将控制权传递给链中的下一个挂钩,以防其他人想要挂钩键盘事件。

所以这一切的最终结果是,每次键盘事件发生时,这个类都会引发 KeyIntercepted 事件。此类的用户可以提供 KeyIntercepted 事件处理程序来做有用的事情,例如将您的银行密码发送给您选择的犯罪集团... *grin*

于 2010-01-12T01:28:53.487 回答
1

委托包装了一个方法,允许像一等对象一样传递它。通常,您使用它来传递回调和注册事件处理程序。

IntPtr是具有略微减少功能的指针的表示形式 - 它基本上是您可以在不放弃类型安全性的情况下使用的指针通常,它用于与本机代码的互操作性。

这两种方法基本上用更“友好”的版本包装了原生 API 调用。

于 2010-01-12T01:30:37.807 回答
1

委托没有任何不受管理的地方。它实际上是基本函数指针的托管和面向对象的友好等价物(在某些类固醇上)。

在这种情况下,它是声明委托类型(说明函数的参数和返回类型)。然后,您可以实例化引用特定函数的该委托的实例(与实例化类型实例的方式非常相似)。

基本示例:

public delegate int AddSomething(int x);

public class Foo
{
    public static void Main(string[] args)
    {
        // the following are equivalent
        AddSomething add1 = Foo.PlusAnything;
        AddSomething add1alt = new AddSomething(Foo.PlusAnything);
        Console.WriteLine(add1(5)); // prints "6"

        // instance delegates, bound to a method on a particular instance
        AddSomething add3 = new Foo(3).AddAnything;
        AddSomething add5 = new Foo(5).AddAnything;
        Console.WriteLine(add3(4)); // prints "7"
        Console.WriteLine(add5(6)); // prints "11"            
    }

    static int PlusOne(int x)  { return x+1; }

    private int y;
    public Foo(int toAdd) { this.y = toAdd; }

    int PlusAnything(int x)  { return x+this.y; } 
}

IntPtr是一种管理方式,它处理大致类似于 void* (指向任何东西的指针)但具有取决于平台的明确定义的大小(因此 32 位平台上的 32 位和 64 位平台上的 64 位) .

当需要保存对某个任意非托管资源的引用时(如本机文件句柄、非托管代码中指向某个缓冲区的指针或指向非托管堆上分配的某个对象或结构的指针),通常使用它。通常以这种方式与非托管代码的交互称为互操作,而通用机制(以及您上面所拥有的机制)称为 P/Invoke。

为了托管 ocde 和互操作的利益,这里有问题的委托正在定义为键盘挂钩发生的回调的签名。它描述了如何将事物转换为其托管等效项的某些方面。通过这样做,您的托管函数(可以在内存中移动)可以传递给一些非托管代码,因为运行时知道这种情况正在发生并确保正确的事情发生。幕后发生了很多“魔术”,因此这一切都可以正常工作,但开发人员(即您)仍然需要知道相关指针的含义以及您应该如何处理它们。

当试图弄清楚如何在 win32 中使用非托管函数时,P/Invoke wiki 非常有用。您以UnhookWindowsHookEx为例,详细说明了如何调用该函数。您仍然需要知道实际功能的作用以及它是如何工作的。

不知道如何处理 IntPtr 并不是一个主要问题,但如果您不知道委托是什么,那么您需要认真学习有关 c#/.net 的知识,然后才能接近此代码库。

于 2010-01-12T01:31:16.510 回答