Проблемы с глобальным хуком
От: HunteX http://troyashka.ru/
Дата: 16.02.12 13:20
Оценка:
Здравствуйте, возникла следующая проблема. Мне необходимо глобально отловить нажатие PrtSc.
Нашел следующий код:

[DllImport("user32.dll")]
static extern IntPtr SetWindowsHookEx(int idHook, KeyboardHookProc callback, IntPtr hInstance, uint threadId);

[DllImport("user32.dll")]
static extern bool UnhookWindowsHookEx(IntPtr hInstance);

[DllImport("user32.dll")]
static extern int CallNextHookEx(IntPtr idHook, int nCode, int wParam, ref KeyboardHookStruct lParam);

[DllImport("kernel32.dll")]
static extern IntPtr LoadLibrary(string lpFileName);

public delegate int KeyboardHookProc(int code, int wParam, ref KeyboardHookStruct lParam);

public struct KeyboardHookStruct
{
    public int VkCode;
    public int ScanCode;
    public int Flags;
    public int Time;
    public int DwExtraInfo;
}

const int WH_KEYBOARD_LL = 13;
const int WM_KEYDOWN = 0x100;
const int WM_KEYUP = 0x101;
const int WM_SYSKEYDOWN = 0x104;
const int WM_SYSKEYUP = 0x105;

public List<Keys> HookedKeys = new List<Keys>();
IntPtr _hhook = IntPtr.Zero;

public event KeyEventHandler KeyDown;
public event KeyEventHandler KeyUp;

public void Hook()
{
    IntPtr hInstance = LoadLibrary("User32");
    _hhook = SetWindowsHookEx(WH_KEYBOARD_LL, HookProc, hInstance, 0);
}

public void Unhook()
{
    UnhookWindowsHookEx(_hhook);
}

public int HookProc(int code, int wParam, ref KeyboardHookStruct lParam)
{
    if (code >= 0)
    {
        var key = (Keys)lParam.VkCode;
        if (HookedKeys.Contains(key))
        {
            var kea = new KeyEventArgs(key);
            if ((wParam == WM_KEYDOWN || wParam == WM_SYSKEYDOWN) && (KeyDown != null))
            {
                KeyDown(this, kea);
            }
            else if ((wParam == WM_KEYUP || wParam == WM_SYSKEYUP) && (KeyUp != null))
            {
                KeyUp(this, kea);
            }
            if (kea.Handled)
                return 1;
        }
    }
    return CallNextHookEx(_hhook, code, wParam, ref lParam);
}

public Form1()
{
    Hook();
    HookedKeys.Add(Keys.PrintScreen);
    KeyUp += GlobalHookKeyUp;
}

void GlobalHookKeyUp(object sender, KeyEventArgs e)
{
    // дальнейшая работа приложения
}


Так вот, проблема заключается в том, что приложение вылетает со следущей ошибкой:

Был произведен обратный вызов делегата "...Form1+KeyboardHookProc::Invoke" типа полученного сборщиком мусора. Это может привести к сбоям приложения, а также к повреждению или утрате данных. При передаче делегатов в неуправляемый код управляемое приложение должно поддерживать их существование, пока не будет гарантировано, что они больше никогда не будут вызваны.


Я понял, что сборщик мусора удаляет объект-делегат и приложение ругается.

Загуглив, наткнулся на класс NativeWindow
Сделал вроде все правильно (сделал AssignHandle хэндла ну и далее по примеру), но все равно возникает такая же ошибка. Подскажите, что делать.
Re: Проблемы с глобальным хуком
От: Пельмешко Россия blog
Дата: 16.02.12 13:33
Оценка:
Здравствуйте, HunteX, Вы писали:

HX>Я понял, что сборщик мусора удаляет объект-делегат и приложение ругается.


Ну так ф почему-бы не попробовать продлить время жизни объекту-делегату?
Например, самым дубовым способом — сохранив в статическую переменную:
someStaticField = new KeyboardHookProc(HookProc);
_hhook = SetWindowsHookEx(WH_KEYBOARD_LL, someStaticField, hInstance, 0);
Re: Проблемы с глобальным хуком
От: adontz Грузия http://adontz.wordpress.com/
Дата: 16.02.12 13:50
Оценка:
Здравствуйте, HunteX, Вы писали:

HX>Подскажите, что делать.


Ошибка тут
SetWindowsHookEx(WH_KEYBOARD_LL, HookProc, hInstance, 0);

Создаваемый делегат нигде не сохраняется
A journey of a thousand miles must begin with a single step © Lau Tsu
Re[2]: Проблемы с глобальным хуком
От: HunteX http://troyashka.ru/
Дата: 16.02.12 13:50
Оценка:
Здравствуйте, Пельмешко, Вы писали:

П>Здравствуйте, HunteX, Вы писали:


HX>>Я понял, что сборщик мусора удаляет объект-делегат и приложение ругается.


П>Ну так ф почему-бы не попробовать продлить время жизни объекту-делегату?

П>Например, самым дубовым способом — сохранив в статическую переменную:
П>
П>someStaticField = new KeyboardHookProc(HookProc);
П>_hhook = SetWindowsHookEx(WH_KEYBOARD_LL, someStaticField, hInstance, 0);
П>


Сделал так:

private static KeyboardHookProc _someStaticField;
public void Hook()
        {
            IntPtr hInstance = LoadLibrary("User32");
            _someStaticField = new KeyboardHookProc(HookProc);
            _hhook = SetWindowsHookEx(WH_KEYBOARD_LL, _someStaticField, hInstance, 0);
        }


Тоже самое
Re[2]: Проблемы с глобальным хуком
От: HunteX http://troyashka.ru/
Дата: 16.02.12 13:52
Оценка:
Здравствуйте, adontz, Вы писали:

A>Здравствуйте, HunteX, Вы писали:


HX>>Подскажите, что делать.


A>Ошибка тут

A>SetWindowsHookEx(WH_KEYBOARD_LL, HookProc, hInstance, 0);

A>Создаваемый делегат нигде не сохраняется


Сделал так:

private static KeyboardHookProc _someStaticField;

public void Hook()
        {
            IntPtr hInstance = LoadLibrary("User32");
            _someStaticField = new KeyboardHookProc(HookProc);
            _hhook = SetWindowsHookEx(WH_KEYBOARD_LL, _someStaticField, hInstance, 0);
        }


Такая же ошибка ...
Re[2]: Проблемы с глобальным хуком
От: HunteX http://troyashka.ru/
Дата: 16.02.12 14:02
Оценка:
Здравствуйте, adontz, Вы писали:

A>Здравствуйте, HunteX, Вы писали:


HX>>Подскажите, что делать.


A>Ошибка тут

A>SetWindowsHookEx(WH_KEYBOARD_LL, HookProc, hInstance, 0);

A>Создаваемый делегат нигде не сохраняется


Причем, возникает только при повторном нажатии PrtSc ...
Re[2]: Проблемы с глобальным хуком
От: HunteX http://troyashka.ru/
Дата: 16.02.12 14:15
Оценка:
Здравствуйте, adontz, Вы писали:

A>Здравствуйте, HunteX, Вы писали:


HX>>Подскажите, что делать.


A>Ошибка тут

A>SetWindowsHookEx(WH_KEYBOARD_LL, HookProc, hInstance, 0);

A>Создаваемый делегат нигде не сохраняется


Все, помоему решилась проблема ... оказывается в конструкторе класса уже вызывалась функция Hook(), так что получается я её повторно вызывал
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.