полууправляемый код с C # - PullRequest
1 голос
/ 12 января 2010
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 ]

4 голосов
/ 12 января 2010

A тип делегата в основном определяет сигнатуру функции или метода: это способ захвата функции или метода как объекта, так что вы можете вызвать этот метод позже. Следовательно, экземпляр делегата в основном является ссылкой на функцию или метод.

IntPtr - это собственный указатель операционной системы - непрозрачная ссылка на фрагмент неуправляемой памяти.

Метод SetHook устанавливает подключаемую процедуру в Windows, так что подключаемая процедура будет вызываться для каждого события клавиатуры в системе. Что такое процедура подключения? Это proc , экземпляр типа делегата LowLevelKeyboardProc. В этом случае proc всегда устанавливается для обращения к вашей функции HookCallback. Так что SetHook в итоге делает указание Windows вызывать HookCallback каждый раз, когда происходит событие клавиатуры .

HookCallback распаковывает информацию о собственной операционной системе, связанную с событием клавиатуры, и вызывает событие KeyIntercepted с этими распакованными данными. Затем он передает управление следующему хуку в цепочке на случай, если кто-то еще захочет перехватить события клавиатуры.

Таким образом, окончательный результат всего этого заключается в том, что каждый раз, когда происходит событие клавиатуры, этот класс вызывает событие KeyIntercepted. Пользователи этого класса могут предоставлять обработчики событий KeyIntercepted для выполнения полезных задач, например для отправки пароля вашего банка в преступный синдикат по вашему выбору ... * ухмылка *

1 голос
/ 12 января 2010

В делегате нет ничего неуправляемого. Фактически это управляемый и объектно-ориентированный дружественный эквивалент (на некоторых стероидах) указателя базовой функции.

В этом контексте объявляет тип делегата (с указанием аргументов функции и возвращаемого типа). Затем вы можете создавать экземпляры этого делегата (почти так же, как экземпляры типа), которые ссылаются на конкретные функции.

базовый пример:

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 - это управляемый способ работы с чем-то похожим на пустоту * (указатель на что-либо), но с четко определенным размером, зависящим от платформы (таким образом, 32 бита на 32-битной платформе) и 64 бита на 64-битной платформе).

Обычно используется, когда необходимо хранить ссылку на некоторый произвольный неуправляемый ресурс (например, собственный дескриптор файла, указатель на некоторый буфер в неуправляемом коде или указатель на некоторый объект или структуру, расположенную в неуправляемой куче) , Часто взаимодействие с неуправляемым кодом таким образом называется взаимодействием, а общий механизм (и тот, что у вас есть выше) называется P / Invoke.

Рассматриваемый здесь делегат определяет для удобства управляемого ocde и взаимодействия сигнатуру обратного вызова, которая происходит для перехвата клавиатуры. Он описывает некоторые аспекты того, как вещи будут преобразованы в их управляемые эквиваленты. Делая это таким образом, ваша управляемая функция (которая может перемещаться в памяти) может быть передана в некоторый неуправляемый код, потому что среда выполнения знает, что это происходит, и гарантирует, что происходит правильно. За кулисами происходит довольно много «магии», так что все это может работать правильно, но от разработчика (то есть вас) все еще ожидают, что значат соответствующие указатели и что вы должны с ними делать.

при попытке понять, как использовать неуправляемые функции в win32, P / Invoke wiki очень полезна. Вы пример для UnhookWindowsHookEx , который подробно описывает, как вызвать эту функцию. Вы все еще должны знать, что делает действительная функция и как она работает.

Незнание того, что делать с IntPtr, не является серьезной проблемой, но если вы не знаете, что такое делегат, у вас есть серьезные знания о c # /. Net, которые нужно сделать, прежде чем вы приблизитесь к этой базе кода.

1 голос
/ 12 января 2010

A делегат оборачивает метод, позволяя передавать его как первоклассный объект. Как правило, вы используете его для передачи обратных вызовов и регистрации обработчиков событий.

IntPtr - это представление указателя с немного сокращенной функциональностью - это, в основном, указатель, который вы можете использовать без потери безопасности типов. Как правило, он используется для взаимодействия с собственным кодом.

Два метода в основном заключают в себе вызовы нативного API с более "дружественными" версиями.

...