Здравствуйте, возникла следующая проблема. Мне необходимо глобально отловить нажатие 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 хэндла ну и далее по примеру), но все равно возникает такая же ошибка. Подскажите, что делать.
Здравствуйте, HunteX, Вы писали:
HX>Я понял, что сборщик мусора удаляет объект-делегат и приложение ругается.
Ну так ф почему-бы не попробовать продлить время жизни объекту-делегату?
Например, самым дубовым способом — сохранив в статическую переменную:
someStaticField = new KeyboardHookProc(HookProc);
_hhook = SetWindowsHookEx(WH_KEYBOARD_LL, someStaticField, hInstance, 0);
Здравствуйте, Пельмешко, Вы писали:
П>Здравствуйте, 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);
}
Тоже самое
Здравствуйте, 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);
}
Такая же ошибка ...
Здравствуйте, adontz, Вы писали:
A>Здравствуйте, HunteX, Вы писали:
HX>>Подскажите, что делать.
A>Ошибка тут
A>SetWindowsHookEx(WH_KEYBOARD_LL, HookProc, hInstance, 0);
A>Создаваемый делегат нигде не сохраняется
Все, помоему решилась проблема ... оказывается в конструкторе класса уже вызывалась функция Hook(), так что получается я её повторно вызывал