您的位置:首页 > 编程语言 > C#

如何在C#中使用全局鼠标、键盘Hook

2007-04-16 13:13 731 查看
How to set a Windows hook in Visual C# .NET

如何在C#中使用全局鼠标、键盘Hook

Posted on 2006-09-22 10:39 loose_went 阅读(758) 评论(19) 编辑 收藏 引用 网摘 所属分类: C# .Net


  今天,有个同事问我,怎样在C#中使用全局钩子?以前写的全局钩子都是用unmanaged C或C++写个DLL来实现,可大家都知道,C#是基于.Net Framework的,是managed,怎么实现全局钩子呢?于是开始到网上搜索,好不容易找到一篇,318804 - HOW TO: Set a Windows Hook in Visual C# .NET,里面详细的说明了如何使用鼠标钩子捕获鼠标的移动等,可是,它只能在Application里起作用,出了Application就没用了,就是说它还是没有实现全局钩子,而且文章结尾处说:“Global Hooks are not supported in the .NET Framework...”,这可怎么办呢?

  别担心,办法总是有的,经过一番摸索以后,发现WH_KEYBORAD_LL和WH_MOUSE_LL这两个low-level的hook可以被安装成全局的,这就好办了,我们不妨用这两个low-level的hook替换掉WH_KEYBORAD和WH_MOUSE,于是开始测试。结果成功了,在C#里实现了全局钩子。

  我们来看一下主要代码段。

  首先倒入所需要的windows函数,主要有三个,SetWindowsHookEX用来安装钩子,UnhookWindowsHookEX用来卸载钩子以及CallNextHookEX用来将hook信息传递到链表中下一个hook处理过程。


[DllImport("user32.dll", CharSet = CharSet.Auto,


CallingConvention = CallingConvention.StdCall, SetLastError = true)]


private static extern int SetWindowsHookEx(


int idHook,


HookProc lpfn,


IntPtr hMod,


int dwThreadId);




[DllImport("user32.dll", CharSet = CharSet.Auto,


CallingConvention = CallingConvention.StdCall, SetLastError = true)]


private static extern int UnhookWindowsHookEx(int idHook);




[DllImport("user32.dll", CharSet = CharSet.Auto,


CallingConvention = CallingConvention.StdCall)]


private static extern int CallNextHookEx(


int idHook,


int nCode,


int wParam,


IntPtr lParam);

[align=left]
  下面是有关这两个low-level hook在Winuser.h中的定义:

[/align]




/**//// <summary>


/// Windows NT/2000/XP: Installs a hook procedure that monitors low-level mouse input events.


/// </summary>


private const int WH_MOUSE_LL = 14;




/**//// <summary>


/// Windows NT/2000/XP: Installs a hook procedure that monitors low-level keyboard input events.


/// </summary>


private const int WH_KEYBOARD_LL = 13;

[align=left]
  在安装全局钩子的时候,我们就要做替换了,将WH_MOUSE和WH_KEYBORAD分别换成WH_MOUSE_LL和WH_KEYBORAD_LL:

[/align]


//install hook


hMouseHook = SetWindowsHookEx(


WH_MOUSE_LL, //原来是WH_MOUSE


MouseHookProcedure,


Marshal.GetHINSTANCE(


Assembly.GetExecutingAssembly().GetModules()[0]),


0);




//install hook


hKeyboardHook = SetWindowsHookEx(


WH_KEYBOARD_LL, //原来是WH_KEYBORAD


KeyboardHookProcedure,


Marshal.GetHINSTANCE(


Assembly.GetExecutingAssembly().GetModules()[0]),


0);

[align=left] [/align]
[align=left]  这样替换了之后,我们就可以实现全局钩子了,而且,不需要写DLL。看一下程序运行情况:

[/align]



  下面是关于鼠标和键盘的两个Callback函数:


private int MouseHookProc(int nCode, int wParam, IntPtr lParam)






{


// if ok and someone listens to our events


if ((nCode >= 0) && (OnMouseActivity != null))






{


//Marshall the data from callback.


MouseLLHookStruct mouseHookStruct = (MouseLLHookStruct)Marshal.PtrToStructure(lParam, typeof(MouseLLHookStruct));




//detect button clicked


MouseButtons button = MouseButtons.None;


short mouseDelta = 0;


switch (wParam)






{


case WM_LBUTTONDOWN:


//case WM_LBUTTONUP:


//case WM_LBUTTONDBLCLK:


button = MouseButtons.Left;


break;


case WM_RBUTTONDOWN:


//case WM_RBUTTONUP:


//case WM_RBUTTONDBLCLK:


button = MouseButtons.Right;


break;


case WM_MOUSEWHEEL:


//If the message is WM_MOUSEWHEEL, the high-order word of mouseData member is the wheel delta.


//One wheel click is defined as WHEEL_DELTA, which is 120.


//(value >> 16) & 0xffff; retrieves the high-order word from the given 32-bit value


mouseDelta = (short)((mouseHookStruct.mouseData >> 16) & 0xffff);


//TODO: X BUTTONS (I havent them so was unable to test)


//If the message is WM_XBUTTONDOWN, WM_XBUTTONUP, WM_XBUTTONDBLCLK, WM_NCXBUTTONDOWN, WM_NCXBUTTONUP,


//or WM_NCXBUTTONDBLCLK, the high-order word specifies which X button was pressed or released,


//and the low-order word is reserved. This value can be one or more of the following values.


//Otherwise, mouseData is not used.


break;


}




//double clicks


int clickCount = 0;


if (button != MouseButtons.None)


if (wParam == WM_LBUTTONDBLCLK || wParam == WM_RBUTTONDBLCLK) clickCount = 2;


else clickCount = 1;




//generate event


MouseEventArgs e = new MouseEventArgs(


button,


clickCount,


mouseHookStruct.pt.x,


mouseHookStruct.pt.y,


mouseDelta);


//raise it


OnMouseActivity(this, e);


}


//call next hook


return CallNextHookEx(hMouseHook, nCode, wParam, lParam);


}



[align=left]
[/align]


private int KeyboardHookProc(int nCode, Int32 wParam, IntPtr lParam)






{


//indicates if any of underlaing events set e.Handled flag


bool handled = false;


//it was ok and someone listens to events


if ((nCode >= 0) && (KeyDown != null || KeyUp != null || KeyPress != null))






{


//read structure KeyboardHookStruct at lParam


KeyboardHookStruct MyKeyboardHookStruct = (KeyboardHookStruct)Marshal.PtrToStructure(lParam, typeof(KeyboardHookStruct));


//raise KeyDown


if (KeyDown != null && (wParam == WM_KEYDOWN || wParam == WM_SYSKEYDOWN))






{


Keys keyData = (Keys)MyKeyboardHookStruct.vkCode;


KeyEventArgs e = new KeyEventArgs(keyData);


KeyDown(this, e);


handled = handled || e.Handled;


}




// raise KeyPress


if (KeyPress != null && wParam == WM_KEYDOWN)






{


bool isDownShift = ((GetKeyState(VK_SHIFT) & 0x80) == 0x80 ? true : false);


bool isDownCapslock = (GetKeyState(VK_CAPITAL) != 0 ? true : false);




byte[] keyState = new byte[256];


GetKeyboardState(keyState);


byte[] inBuffer = new byte[2];


if (ToAscii(MyKeyboardHookStruct.vkCode,


MyKeyboardHookStruct.scanCode,


keyState,


inBuffer,


MyKeyboardHookStruct.flags) == 1)






{


char key = (char)inBuffer[0];


if ((isDownCapslock ^ isDownShift) && Char.IsLetter(key)) key = Char.ToUpper(key);


KeyPressEventArgs e = new KeyPressEventArgs(key);


KeyPress(this, e);


handled = handled || e.Handled;


}


}




// raise KeyUp


if (KeyUp != null && (wParam == WM_KEYUP || wParam == WM_SYSKEYUP))






{


Keys keyData = (Keys)MyKeyboardHookStruct.vkCode;


KeyEventArgs e = new KeyEventArgs(keyData);


KeyUp(this, e);


handled = handled || e.Handled;


}




}




//if event handled in application do not handoff to other listeners


if (handled)


return 1;


else


return CallNextHookEx(hKeyboardHook, nCode, wParam, lParam);


}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: