您好,欢迎访问三七文档
当前位置:首页 > 商业/管理/HR > 质量控制/管理 > 整理的一些关于C#的文章,希望能对大家有所帮助
整理的一些关于C#的文章,希望能对大家有所帮助.1:C#+低级WindowsAPI钩子拦截键盘输入摘要在家里,婴儿和其它动物可能会重击你的计算机键盘,致使出现各种无法预言的结果。本文中的这个C#示例应用程序将向你展示如何基于Windows钩子API来实现在击键造成任何危害之前捕获它们。一.简介猫和婴儿有很多共同之处。他们都喜欢吃家中养植的植物,都非常讨厌关门。他们也都爱玩弄你的键盘,结果是,你正发送给你的老板的电子邮件可能是以半截句子发送出去的,你的Excel帐户也被加入了一些乱七八糟的内容,并且你还没有注意到,当打开Windows资源管理器时,若干文件已经被移到了回收站!其解决方案是,开发一个应用程序实现如下功能:只要键盘处于威胁状态你就可以进行切换,并确保任何键盘输入活动都不会造成危害。本文想展示如何使用一种低级WindowsAPI钩子在一个C#应用程序中实现键盘控制。下图是本文示例程序的一个运行快照。二.背景其实,已经存在许多有关于Windows钩子的文章和示例代码,并且已经有人编写过与本文几乎一样的C++示例程序。然而,当我搜索相应的C#应用程序的源码时,却找到极少的.NET示例,而且没有一个程序能够提供一个方便的自包含的C#类。.NET框架能够使你以托管方式来存取你最常使用的键盘事件(通过KeyPress,KeyUp和KeyDown)。遗憾的是,这些事件都不能被用来停止Windows组合键(如Alt+Tab或Windows开始键),从而允许用户远离某一个应用程序。本文的想法在操作系统级上捕获键盘事件而不是通过框架级来实现。为此,应用程序需要使用WindowsAPI函数来把它自身添加到应用程序钩子链中以监听来自操作系统的键盘消息。当它收到这种类型的消息时,该应用程序能够选择性地传递消息,或者进行正常处理,或者镇压它以便不再有其它应用程序(包括Windows)来影响它。本文正是想解释其实现机理。然而,请注意,本文中的代码仅适用于基于NT版本的Windows(NT,2000和XP),并且无法使用这个方法来停用Ctrl+Alt+Delete。有关于如何实现这一点,你可以参考MSDN有关资料。三.使用代码为了易于使用,我在本文中提供了两个独立的zip文件。一个仅包含KeyboardHook类,这是本文介绍的重点。另一个是一个完整的微软VisualC#2005ExpressEdition应用程序工程,名叫BabyKeyboardBash,它实现显示击键的名字或彩色的形状以响应于击键。四.实例化类键盘钩子是通过keyboard.cs中的KeyboardHook类来建立和管理的。这个类实现了IDisposable接口,因此,实例化它的最简单的方法是在应用程序的Main()方法中使用using关键字来封装Application.Run()调用。这将确保只要该应用程序开始即建立钩子并且,更重要的是,当该应用程序结束时立即使这个钩子失效。这个类引发一个事件来警告应用程序已经有键被按下,因此主表单能够存取在Main()方法中创建的KeyboardHook实例就显得非常重要;最简单的方法是把这个实例存储在一个公共成员变量中。KeyboardHook提供了三种构造器来启用或禁用某些设置:•KeyboardHook():捕获所有击键,没有任何内容传递到Windows或另外的应用程序。•KeyboardHook(stringparam):把参数串转换为Parameters枚举中的值之一,然后调用下面的构造器:•KeyboardHook(KeyboardHook.Parametersenum):根据从Parameters枚举中选择的值的不同,分别启动下列设置:oParameters.AllowAltTab:允许用户使用Alt+Tab切换到另外的应用程序。oParameters.AllowWindowsKey:允许用户使用Ctrl+Esc或一种Windows键存取任务栏和开始菜单。oParameters.AllowAltTabAndWindows:启用Alt+Tab,Ctrl+Esc和Windows键。oParameters.PassAllKeysToNextApp:如果该参数为true,那么所有的击键将被传递给任何其它监听应用程序(包括Windows)。当击键继续被键盘钩子捕获时,启用Alt+Tab和/或Windows键允许实际使用该计算机者切换到另一个应用程序并且使用鼠标与之交互。PassAllKeysToNextApp设置有效地禁用了击键捕获;这个类也是建立一个低级键盘钩子并且引发它的KeyIntercepted事件,但是它还负责把键盘事件传递到另一个监听程序。因此,实例化该类以捕获所有击键的方法如下:publicstaticKeyboardHookkh;[STAThread]staticvoidMain(){//其它代码using(kh=newKeyboardHook()){Application.Run(newForm1());}五.处理KeyIntercepted事件当一外键被按下时,这个KeyboardHook类激活一个包含一些KeyboardHookEventArgs的KeyIntercepted事件。这是通过一个KeyboardHookEventHandler类型的方法使用以下方式来实现的:kh.KeyIntercepted+=newKeyboardHook.KeyboardHookEventHandler(kh_KeyIntercepted);这个KeyboardHookEventArgs返回关于被按下键的下列信息:•KeyName:键名,通过把捕获的键代码强制转换为System.Windows.Forms.Keys而获得。•KeyCode:由键盘钩子返回的原来的键代码•PassThrough:指出是否这个KeyboardHook实例被配置以允许该击键传递到其它应用程序。如果你想允许一用户使用Alt+Tab或Ctrl+Esc/Windows键切换到其它的应用程序的话,那么对之进行检查是很有用的。然后,使用一个具有适当签名的方法来执行击键所调用的任何任务。下面是一个示例片断:voidkh_KeyIntercepted(KeyboardHookEventArgse){//检查是否这个键击事件被传递到其它应用程序并且停用TopMost,以防他们需要调到前端if(e.PassThrough){this.TopMost=false;}ds.Draw(e.KeyName);}本文的剩下部分将解释低级键盘钩子是如何在KeyboardHook中实现的。六.实现一个低级WindowsAPI键盘钩子在user32.dll中,WindowsAPI包含三个方法来实现此目的:•SetWindowsHookEx,它负责建立键盘钩子•UnhookWindowsHookEx,它负责移去键盘钩子•CallNextHookEx,它负责把击键信息传递到下一个监听键盘事件的应用程序创建一个能够拦截键盘的应用程序的关键是,实现前面两个方法,而放弃第三个。结果是,任何击键都只能传递到这个应用程序中。为了实现这一目标,第一步是包括System.Runtime.InteropServices命名空间并且导入API方法,首先是SetWindowsHookEx:usingSystem.Runtime.InteropServices...//在类内部:[DllImport(user32.dll,CharSet=CharSet.Auto,SetLastError=true)]privatestaticexternIntPtrSetWindowsHookEx(intidHook,LowLevelKeyboardProclpfn,IntPtrhMod,uintdwThreadId);导入UnhookWindowsHookEx和CallNextHookEx的代码请见后面的讨论。下一步是调用SetWindowsHookEx来建立钩子,这时需要传递下列四个参数:•idHook:这个数字决定了要建立的钩子的类型。例如,SetWindowsHookEx可以被用于钩住鼠标事件(当然还有其它事件)。在本文情况下,我们仅对13有兴趣,这是键盘钩子的id。为了使代码更易读些,我们把它赋值给一个常数WH_KEYBOARD_LL。•Lpfn:这是一个指向函数的长指针,该函数将负责处理键盘事件。在C#中,指针是通过传递一个代理类型的实例而获得的,从而使之引用一个适当的方法。这是我们在每次使用钩子时所调用的方法。这里值得注意的是,这个代理实例需要被存储于这个类的一个成员变量中。这是为了防止一旦第一个方法调用结束它会被作为垃圾回收。•hMod:建立钩子的应用程序的一个实例句柄。我找到的绝大多数实例仅把它设置为IntPtr.Zero,理由是不大可能存在该应用程序的多个实例。然而,这部分代码使用了来自于kernel32.dll的GetModuleHandle来标识准确的实例从而使这个类更具灵活性。•dwThreadId:当前进程的id。把它设置为0可以使这个钩子成为全局构子,这是相应于一个低级键盘钩子的正确设置。SetWindowsHookEx返回一个钩子id,这个id将被用于当应用程序结束时从钩子链中脱钩,因此它需要存储在一个成员变量中以备将来使用。KeyboardHook类中的相关代码如下:privateHookHandlerDelegateproc;privateIntPtrhookID=IntPtr.Zero;privateconstintWH_KEYBOARD_LL=13;publicKeyboardHook(){proc=newHookHandlerDelegate(HookCallback);using(ProcesscurProcess=Process.GetCurrentProcess())using(ProcessModulecurModule=curProcess.MainModule){hookID=SetWindowsHookEx(WH_KEYBOARD_LL,proc,GetModuleHandle(curModule.ModuleName),0);}}七.处理键盘事件如前面所提及,SetWindowsHookEx需要一个到被用来处理键盘事件的回调函数的指针。它期望有一个使用如下签名的函数:LRESULTCALLBACKLowLevelKeyboardProc(intnCode,WPARAMwParam,LPARAMlParam);其实,建立一个函数指针的C#方法使用了一个代理,因此,向SetWindowsHookEx指出它需要的内容的第一步是使用正确的签名来声明一个代理:privatedelegateIntPtrHookHandlerDelegate(intnCode,IntPtrwParam,refKBDLLHOOKSTRUCTlParam);然后,使用相同的签名编写一个回调方法;这个方法将包含实际上处理键盘事件的所有代码。在KeyboardHook的情况下,它检查是否击键应该被传递给其它应用程序并且接下来激发KeyIntercepted事件。下面是一个简化版本的不带有击键处理代码的情况:privateconstintWM_KEYDOWN=0x0100;privateconstintWM_SYSKEYDOWN=0x0104;privateIntPtrHookCallback(intnCode,IntPtrwParam,refKBDLLHOOKSTRUCTlParam){//仅为KeyDown事件过滤wParam,否则该代码将再次执行-对于每一次击键(也就是,相应于KeyDown和KeyUp)//WM_SYSKEYDOWN是捕获Alt相关组合键所必需的if(nCode=0&&(wParam==(IntPtr)WM_KEYDOWN||wParam==(IntPtr)WM_SY
本文标题:整理的一些关于C#的文章,希望能对大家有所帮助
链接地址:https://www.777doc.com/doc-6163851 .html