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とは何か、2 つのメソッドとそれらが行ごとに何をするのかに興味があります。

誰か時間があればありがとう

4

3 に答える 3

4

デリゲート型は、基本的に関数またはメソッドのシグネチャを指定します。これは、後でそのメソッドを呼び出すことができるように、関数またはメソッドをオブジェクトとしてキャプチャする方法です。したがって、デリゲート インスタンスは基本的に関数またはメソッドへの参照です。

IntPtrは、オペレーティング システムのネイティブ ポインターであり、アンマネージ メモリへの不透明な参照です。

SetHook メソッドは、システム内のすべてのキーボード イベントに対してフック プロシージャが呼び出されるように、フック プロシージャを Windows にインストールします。フック手順とは何ですか? デリゲート型のインスタンスであるprocです。LowLevelKeyboardProcこの場合、procは常にHookCallback関数を参照するように設定されています。つまり、キーボード イベントが発生するたびに HookCallback を呼び出すように Windows に指示することになりSetHookます。

HookCallback は、キーボード イベントに関連付けられたネイティブ オペレーティング システム情報をアンパックし、そのアンパックされたデータで KeyIntercepted イベントを発生させます。次に、他の誰かがキーボード イベントをフックしたい場合に備えて、チェーン内の次のフックに制御を渡します。

したがって、これらすべての最終結果は、キーボード イベントが発生するたびに、このクラスが KeyIntercepted イベントを発生させることです。このクラスのユーザーは、KeyIntercepted イベント ハンドラーを提供して、たとえば銀行のパスワードを任意の犯罪シンジケートに送信するなど、便利なことを行うことができます... *にやにや*

于 2010-01-12T01:28:53.487 に答える
1

デリゲートはメソッドをラップし、ファースト クラス オブジェクトのように渡すことができます。通常、これを使用してコールバックを渡し、イベント ハンドラーを登録します。

IntPtrは、機能がわずかに縮小されたポインターの表現です。基本的には、タイプ セーフを失わずに使用できるポインターです通常、ネイティブ コードとの相互運用性のために使用されます。

2 つの方法は基本的に、ネイティブ API 呼び出しをより「使いやすい」バージョンでラップします。

于 2010-01-12T01:30:37.807 に答える
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 と相互運用性のために、キーボード フックに対して発生するコールバックのシグネチャを定義しています。物事が管理された同等のものに変換される方法の特定の側面について説明します。このようにすることで、マネージ関数 (メモリ内を移動できる) をアンマネージ コードに渡すことができます。これは、ランタイムがこれが発生していることを認識し、正しいことが確実に行われるようにするためです。舞台裏では非常に多くの「魔法」が行われているため、これはすべて正しく機能しますが、開発者 (つまり、あなた) は、関連するポインタが何を意味し、何をすべきかを知っている必要があります。

win32 でアンマネージ関数を使用する方法を考えようとするとき、P/Invoke wiki は非常に便利です。その関数を呼び出す方法を詳しく説明するUnhookWindowsHookExの例です。ただし、実際の関数が何を行い、どのように機能するかを知っている必要があります。

IntPtr で何をすべきかわからないことは大きな問題ではありませんが、デリゲートが何であるかわからない場合は、このコード ベースに近づく前に、c#/.net について真剣に学ぶ必要があります。

于 2010-01-12T01:31:16.510 に答える