这是键盘钩码:
class globalKeyboardHook
{
#region Constant, Structure and Delegate Definitions
public delegate int keyboardHookProc(int code, int wParam, ref keyboardHookStruct lParam);
public static keyboardHookProc callbackDelegate;
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;
#endregion
#region Instance Variables
public List<Keys> HookedKeys = new List<Keys>();
private static IntPtr hhook = IntPtr.Zero;
#endregion
#region Events
public event KeyEventHandler KeyDown;
public event KeyEventHandler KeyUp;
#endregion
#region Constructors and Destructors
public globalKeyboardHook()
{
hook();
GC.KeepAlive(callbackDelegate);
}
~globalKeyboardHook()
{
unhook();
}
#endregion
#region Public Methods
public void hook()
{
IntPtr hInstance = LoadLibrary("User32");
callbackDelegate = new keyboardHookProc(hookProc);
hhook = SetWindowsHookEx(WH_KEYBOARD_LL, callbackDelegate, hInstance, 0);
if (hhook == IntPtr.Zero) throw new Win32Exception();
}
public void unhook()
{
bool ok = UnhookWindowsHookEx(hhook);
if (!ok) throw new Win32Exception();
callbackDelegate = null;
}
public int hookProc(int code, int wParam, ref keyboardHookStruct lParam)
{
if (code >= 0)
{
Keys key = (Keys)lParam.vkCode;
if (HookedKeys.Contains(key))
{
KeyEventArgs 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); // Exception on this line
}
#endregion
#region DLL imports
[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);
#endregion
}
当我在Child Form构造函数中初始化它时,首先没有任何事情发生,你可以按下你想要的所有东西,但没有任何东西可以进入事件:
private globalKeyboardHook kh = new globalKeyboardHook();
public FrmMainForm(FrmVideo owner)
{
InitializeComponent();
_videoForm = owner;
try
{
_videoDevices = new FilterInfoCollection(FilterCategory.VideoInputDevice);
if (_videoDevices.Count == 0)
{
throw new ApplicationException();
}
foreach (FilterInfo device in _videoDevices)
{
camerasCombo.Items.Add(device.Name);
}
camerasCombo.SelectedIndex = 1;
}
catch (ApplicationException)
{
camerasCombo.Items.Add("No local capture devices");
_videoDevices = null;
}
kh.KeyUp += new KeyEventHandler(kh_KeyUp);
kh.hook();
}
void kh_KeyUp(object sender, KeyEventArgs e)
{
if (e.KeyCode == Keys.F12)
_videoForm.TakeOver = !_videoForm.TakeOver;
if (e.KeyCode == Keys.Escape)
Application.Exit();
}
在我拨打Aforge代码以便从网络摄像头中捕获之前,这会在父表单上开始流式传输:
var videoSource = new VideoCaptureDevice(_videoDevices[camerasCombo.SelectedIndex].MonikerString)
{
DesiredFrameSize = new Size(Globals.FrameWidth, Globals.FrameHeight),
DesiredFrameRate = 12
};
if (videoSource != null)
{
_videoForm.Device = videoSource;
_videoForm.Start();
button1.Enabled = false;
}
在任何按键后,我得到: 在返回下一个钩子时检测到CallbackOnCollectedDelegate,有什么想法吗?
哦,我正在解雇处理表格:
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
kh.unhook();
base.Dispose(disposing);
}
答案 0 :(得分:2)
这需要通过心理调试并推断出您没有记录的内容。奇怪的是,当您调用CallNextHookEx()时会触发MDA。这有点奇怪,你的钩子程序的回调实际上是有效的。没有收集该委托对象。 next 挂钩过程调用失败。
有一个简单的解释:你不止一次调用了SetWindowsHookEx()。现在使用静态变量来存储委托对象将严重咬人,正如静态变量通常所做的那样,它只能存储一个委托对象。第二次调用hook()时,它将覆盖第一个钩子的委托,因此不再阻止垃圾收集。这确实在CallNextHookEx()上触发了MDA,因为这将调用第一个钩子的钩子过程。
所以你的hook()方法需要改进:
public void hook()
{
if (callbackDelegate != null)
throw new InvalidOperationException("Cannot hook more than once");
// etc..
}
多次挂钩实际上并不违法,Windows并不介意。只是不要声明变量static。