使用c#的半非托管代码

时间:2010-01-12 01:24:12

标签: c# keyboard hook intptr

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 是什么以及两种方法以及它们逐行进行的操作。

谢谢,如果有人有时间

3 个答案:

答案 0 :(得分:4)

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

IntPtr 是一个操作系统本机指针 - 对一段非托管内存的不透明引用。

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

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

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

答案 1 :(得分:1)

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

IntPtr 是一个功能略有缩减的指针的表示 - 它基本上是一个指针,你可以使用而不会降低类型安全性。通常,它用于与本机代码的互操作性。

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

答案 2 :(得分:1)

关于代表没有任何管理权。它实际上是基本函数指针的托管和面向对象的友好等价物(在一些类固醇上)。

在此上下文中是声明委托类型(声明函数的参数和返回类型)。然后,您可以实例化该委托的实例(与实例化Type的实例的方式非常相似),这些实例引用特定的函数。

基本示例:

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和interop的好处,定义了键盘钩子发生的回调签名。它描述了如何将事物转换为其托管等价物的某些方面。通过这种方式,您可以将托管函数(可以在内存中移动)传递给某些非托管代码,因为运行时知道这种情况正在发生,并确保正确的事情发生。在幕后发生了很多“魔术”,所以这一切都可以正常工作,但开发人员(即你)仍然需要知道相关指针的含义以及你应该用它们做什么。

当试图找出如何在win32中使用非托管函数时,P / Invoke wiki非常有用。您的示例UnhookWindowsHookEx详细说明了如何调用该函数。你仍然需要知道the actual function做了什么以及它是如何工作的。

不知道如何处理IntPtr不是一个主要问题,但是如果你不知道委托是什么,那么在你应该去这个代码库附近的任何地方之前,你都要认真学习c#/ .net。< / p>