使用 c# 的半非托管代码

发布于 2024-08-18 01:23:59 字数 2671 浏览 7 评论 0原文

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

谢谢,如果有人有时间的话

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);
}

so I have no idea what this code means even though its the core of my program. It hooks a keyboard press event and sends it to my program. Can anyone take there precious time and explain a few things to me. I understand the args class so you can skip that. I am mostly interested in what a delegate is, what an IntPtr is and the two methods and what they do line by line.

thanks if anyone has the time

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

独行侠 2024-08-25 01:23:59

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

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

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

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

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

A delegate type basically specifies the signature of a function or method: it's a way of capturing a function or method as an object, so that you can call that method later. A delegate instance is therefore basically a reference to a function or method.

An IntPtr is an operating system native pointer -- an opaque reference to a piece of unmanaged memory.

The SetHook method is installing a hook procedure into Windows, so that the hook procedure will be called for every keyboard event in the system. What is the hook procedure? It is proc, an instance of the LowLevelKeyboardProc delegate type. In this case, proc is always being set to refer to your HookCallback function. So what SetHook ends up doing is telling Windows to call HookCallback every time a keyboard event happens.

HookCallback is unpacking the native operating system information associated with the keyboard event, and raising the KeyIntercepted event with that unpacked data. It's then passing control to the next hook in the chain, in case anybody else is wanting to hook keyboard events.

So the final result of all this is that every time a keyboard event happens, this class raises the KeyIntercepted event. Users of this class can provide KeyIntercepted event handlers to do useful things, for example sending your bank password to the crime syndicate of your choice... *grin*

陌若浮生 2024-08-25 01:23:59

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

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

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

A delegate wraps a method, allowing to pass it around like a first-class object. Typically, you use it to pass callbacks and register event handlers.

An IntPtr is a representation of a pointer with slightly-reduced functionality - it's basically a pointer you can use without dropping type-safety. Typically, it's used for interoperability with native code.

The two methods basically wrap the native API calls with more "friendly" versions.

允世 2024-08-25 01:23:59

代表没有什么是不受管理的。事实上,它是基本函数指针的托管和面向对象友好的等价物(在某些方面)。

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

基本示例:

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,然后才能接近此代码库。

There is nothing unmanaged about a delegate. It is in fact the managed and Object Oriented friendly equivalent (on some steroids) of the basic function pointer.

In this context is it declaring the delegate type (stating the function's arguments and return type). You can then instantiate instances of that delegate (in much the same way you instantiate instances of a Type) which refer to specific functions.

basic example:

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 is a managed way of working with the something roughly like a void* (a pointer to anything) but with a well defined size that is dependent on the platform (so 32bits on a 32 bit platform and 64 bits on a 64 bit platform).

It is commonly used when there is a need to hold a reference to some arbitrary unmanaged resource (like a native file handle,a pointer to some buffer in unmanaged code or a pointer to some object or structure allocated on the unmanaged heap). Often interaction with unmanaged code in this way is called interop, and the common mechanism (and the one you have above) is called P/Invoke.

The delegate in question here is defining, for the benefit of the managed ocde and the interop, the signature of the callback that occurs for the keyboard hook. It describes certain aspects of how things will be converted to their managed equivalents. By doing it this way your managed function (which can move about in memory) can be passed to some unmanaged code because the runtime knows this is happening and it ensures that the right thing happens. There is quite a lot of 'magic' happening here behind the scenes so that this can all work correctly but the developer (i.e. you) is still expected to know what the relevant pointers means and what you are supposed to do with them.

when trying to work out how to use unmanaged functions in win32 the P/Invoke wiki is very useful. You example for the UnhookWindowsHookEx which details how to call that function. You would still be expected to know what the actual function does and how it works though.

Not knowing what to do with an IntPtr is not a major issue but if you don't know what a delegate is you have some serious learning about c#/.net to do before you should go anywhere near this code base.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文