大学IT网 - 最懂大学生的IT学习网站! QQ资料交流群:367606806
当前位置:大学IT网 > C#技巧 > 如何在C#中使用全局鼠标、键盘Hook

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

关键词:C#全局鼠标键盘Hook  阅读(1009) 赞(18)

[摘要]本文是对如何在C#中使用全局鼠标、键盘Hook的讲解,对学习C#编程技术有所帮助,与大家分享。

今天,有个同事问我,怎样在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处理过程。

C#代码
    1. [DllImport("user32.dll",CharSet=CharSet.Auto,
    2. CallingConvention=CallingConvention.StdCall,SetLastError=true)]
    3. privatestaticexternintSetWindowsHookEx(
    4. intidHook,
    5. HookProclpfn,
    6. IntPtrhMod,
    7. intdwThreadId);
    8. [DllImport("user32.dll",CharSet=CharSet.Auto,
    9. CallingConvention=CallingConvention.StdCall,SetLastError=true)]
    10. privatestaticexternintUnhookWindowsHookEx(intidHook);
    11. [DllImport("user32.dll",CharSet=CharSet.Auto,
    12. CallingConvention=CallingConvention.StdCall)]
    13. privatestaticexternintCallNextHookEx(
    14. intidHook,
    15. intnCode,
    16. intwParam,
    17. IntPtrlParam);
    18.   下面是有关这两个low-levelhook在Winuser.h中的定义:
    19. ///<summary>
    20. ///WindowsNT/2000/XP:Installsahookprocedurethatmonitorslow-levelmouseinputevents.
    21. ///</summary>
    22. privateconstintWH_MOUSE_LL=14;
    23. ///<summary>
    24. ///WindowsNT/2000/XP:Installsahookprocedurethatmonitorslow-levelkeyboardinputevents.
    25. ///</summary>
    26. privateconstintWH_KEYBOARD_LL=13;
    27.   在安装全局钩子的时候,我们就要做替换了,将WH_MOUSE和WH_KEYBORAD分别换成WH_MOUSE_LL和WH_KEYBORAD_LL:
    28. //installhook
    29. hMouseHook=SetWindowsHookEx(
    30. WH_MOUSE_LL, //原来是WH_MOUSE
    31. MouseHookProcedure,
    32. Marshal.GetHINSTANCE(
    33. Assembly.GetExecutingAssembly().GetModules()[0]),
    34. 0);
    35. //installhook
    36. hKeyboardHook=SetWindowsHookEx(
    37. WH_KEYBOARD_LL,//原来是WH_KEYBORAD
    38. KeyboardHookProcedure,
    39. Marshal.GetHINSTANCE(
    40. Assembly.GetExecutingAssembly().GetModules()[0]),
    41. 0);
    42.   这样替换了之后,我们就可以实现全局钩子了,而且,不需要写DLL。看一下程序运行情况:
    43.   下面是关于鼠标和键盘的两个Callback函数:
    44. privateintMouseHookProc(intnCode,intwParam,IntPtrlParam)
    45. {
    46. //ifokandsomeonelistenstoourevents
    47. if((nCode>=0)&&(OnMouseActivity!=null))
    48. {
    49. //Marshallthedatafromcallback.
    50. MouseLLHookStructmouseHookStruct=(MouseLLHookStruct)Marshal.PtrToStructure(lParam,typeof(MouseLLHookStruct));
    51. //detectbuttonclicked
    52. MouseButtonsbutton=MouseButtons.None;
    53. shortmouseDelta=0;
    54. switch(wParam)
    55. {
    56. caseWM_LBUTTONDOWN:
    57. //caseWM_LBUTTONUP:
    58. //caseWM_LBUTTONDBLCLK:
    59. button=MouseButtons.Left;
    60. break;
    61. caseWM_RBUTTONDOWN:
    62. //caseWM_RBUTTONUP:
    63. //caseWM_RBUTTONDBLCLK:
    64. button=MouseButtons.Right;
    65. break;
    66. caseWM_MOUSEWHEEL:
    67. //IfthemessageisWM_MOUSEWHEEL,thehigh-orderwordofmouseDatamemberisthewheeldelta.
    68. //OnewheelclickisdefinedasWHEEL_DELTA,whichis120.
    69. //(value>>16)&0xffff;retrievesthehigh-orderwordfromthegiven32-bitvalue
    70. mouseDelta=(short)((mouseHookStruct.mouseData>>16)&0xffff);
    71. //TODO:XBUTTONS(Ihaventthemsowasunabletotest)
    72. //IfthemessageisWM_XBUTTONDOWN,WM_XBUTTONUP,WM_XBUTTONDBLCLK,WM_NCXBUTTONDOWN,WM_NCXBUTTONUP,
    73. //orWM_NCXBUTTONDBLCLK,thehigh-orderwordspecifieswhichXbuttonwaspressedorreleased,
    74. //andthelow-orderwordisreserved.Thisvaluecanbeoneormoreofthefollowingvalues.
    75. //Otherwise,mouseDataisnotused.
    76. break;
    77. }
    78. //doubleclicks
    79. intclickCount=0;
    80. if(button!=MouseButtons.None)
    81. if(wParam==WM_LBUTTONDBLCLK||wParam==WM_RBUTTONDBLCLK)clickCount=2;
    82. elseclickCount=1;
    83. //generateevent
    84. MouseEventArgse=newMouseEventArgs(
    85. button,
    86. clickCount,
    87. mouseHookStruct.pt.x,
    88. mouseHookStruct.pt.y,
    89. mouseDelta);
    90. //raiseit
    91. OnMouseActivity(this,e);
    92. }
    93. //callnexthook
    94. returnCallNextHookEx(hMouseHook,nCode,wParam,lParam);
    95. }
    96. privateintKeyboardHookProc(intnCode,Int32wParam,IntPtrlParam)
    97. {
    98. //indicatesifanyofunderlaingeventssete.Handledflag
    99. boolhandled=false;
    100. //itwasokandsomeonelistenstoevents
    101. if((nCode>=0)&&(KeyDown!=null||KeyUp!=null||KeyPress!=null))
    102. {
    103. //readstructureKeyboardHookStructatlParam
    104. KeyboardHookStructMyKeyboardHookStruct=(KeyboardHookStruct)Marshal.PtrToStructure(lParam,typeof(KeyboardHookStruct));
    105. //raiseKeyDown
    106. if(KeyDown!=null&&(wParam==WM_KEYDOWN||wParam==WM_SYSKEYDOWN))
    107. {
    108. KeyskeyData=(Keys)MyKeyboardHookStruct.vkCode;
    109. KeyEventArgse=newKeyEventArgs(keyData);
    110. KeyDown(this,e);
    111. handled=handled||e.Handled;
    112. }
    113. //raiseKeyPress
    114. if(KeyPress!=null&&wParam==WM_KEYDOWN)
    115. {
    116. boolisDownShift=((GetKeyState(VK_SHIFT)&0x80)==0x80?true:false);
    117. boolisDownCapslock=(GetKeyState(VK_CAPITAL)!=0?true:false);
    118. byte[]keyState=newbyte[256];
    119. GetKeyboardState(keyState);
    120. byte[]inBuffer=newbyte[2];
    121. if(ToAscii(MyKeyboardHookStruct.vkCode,
    122. MyKeyboardHookStruct.scanCode,
    123. keyState,
    124. inBuffer,
    125. MyKeyboardHookStruct.flags)==1)
    126. {
    127. charkey=(char)inBuffer[0];
    128. if((isDownCapslock^isDownShift)&&Char.IsLetter(key))key=Char.ToUpper(key);
    129. KeyPressEventArgse=newKeyPressEventArgs(key);
    130. KeyPress(this,e);
    131. handled=handled||e.Handled;
    132. }
    133. }
    134. //raiseKeyUp
    135. if(KeyUp!=null&&(wParam==WM_KEYUP||wParam==WM_SYSKEYUP))
    136. {
    137. KeyskeyData=(Keys)MyKeyboardHookStruct.vkCode;
    138. KeyEventArgse=newKeyEventArgs(keyData);
    139. KeyUp(this,e);
    140. handled=handled||e.Handled;
    141. }
    142. }
    143. //ifeventhandledinapplicationdonothandofftootherlisteners
    144. if(handled)
    145. return1;
    146. else
    147. returnCallNextHookEx(hKeyboardHook,nCode,wParam,lParam);
    148. }


相关评论