最近用VB做外挂,模拟鼠标实现自动化操作。发现驱动级模拟,一直存在问题。今天终于解决了,记录下.
---------------------------------------------------------------------------------
系统环境:win7 64位,VB 32位
winIO环境: 3.0环境
下载地址:www.internals.com
---------------------------------------------------------------------------------
WinIO是一款免费、开源的系统组件,你可以在www.internals.com上面免费下载它的
源码。在最新版本3.0中,增加了对64位 Windows操作系统的支持。我就是利用它的功能,
实现了驱动级模拟按键。在我使用的WinIO 3.0中,里面有四个bin 文件,分别是
WinIO32.dll、WinIO64.dll、WinIO32.sys、WinIO64.sys。sys文件是实现核心功能的驱动,
dll文件是封装驱动功能的接口。由于我的系统是64 位系统,使用了VB做界面编程,所以
仅需要 WinIO32.dll和 WinIO64.sys。dll
- VB调试的时候,要把 WinIO32.dll和 WinIO64.sys 文件拷贝到VB安装目录下
- 生成exe文件后,WinIO32.dll和 WinIO64.sys 跟exe文件保持在同目录下即可
- 关于数字签名:
WinIO64.sys没有正式的数字签名,只有测试签名。要使它能成功加载,
必须打开测试模式(cmd里切换到 system32目录再输入 bcdedit /set testsigning on),
然后根据以下步骤信任WinIO64.sys的测试签名:
1.打开 WinIO64.sys的属性框,翻到“数字签名”选项卡,点击“详细信息”
2.在新出来的对话框中点击“查看证书”
3.在又新出来的对话框中点击“安装证书”
4.点击“下一步”,然后选择“将所有的证书放入下列存储”
5.点击浏览,选择“受信任的根证书发布机构”
受信任的根证书发布界面
6.点击“下一步”,然后点击“完成”
7.在弹出的“安全性警告”对话框中选择“是”,才能导入成功
实现方式:
调用:
- Private Sub Command6_Click()
- If InitializeWinIo = False Then
- '用InitializeWinIo函数加载驱动程序,如果成功会返回true,否则返回false
- MsgBox "驱动程序加载失败!"
- Else
- Dim hwnd As Long
- hwnd = Shell("Notepad.exe",vbNormalFocus)
- Sleep 1000
- '模拟按下 alt+F 键
- MyKeyDownEx VK_MENU
- Sleep 200
- MyKeyDown VK_F
- MyKeyUp VK_F '模拟按下并释放A键
- MyKeyUpEx VK_MENU
- Sleep 500
- '模拟按下 ctl+O 键
- MyKeyDownEx VK_Control
- Sleep 200
- MyKeyDown VK_O
- MyKeyUp VK_O '模拟按下并释放A键
- MyKeyUpEx VK_Control
- ShutdownWinIo '程序结束时记得用ShutdownWinIo函数卸载驱动程序
- End If
- End Sub
模块:
- Option Explicit
- Declare Function MapPhysToLin Lib "WinIo32.dll" (ByVal PhysAddr As Long,ByVal PhysSize As Long,ByRef PhysMemHandle) As Long
- Declare Function UnmapPhysicalMemory Lib "WinIo32.dll" (ByVal PhysMemHandle,ByVal LinAddr) As Boolean
- Declare Function GetPhysLong Lib "WinIo32.dll" (ByVal PhysAddr As Long,ByRef PhysVal As Long) As Boolean
- Declare Function SetPhysLong Lib "WinIo32.dll" (ByVal PhysAddr As Long,ByVal PhysVal As Long) As Boolean
- Declare Function GetPortVal Lib "WinIo32.dll" (ByVal PortAddr As Integer,ByRef PortVal As Long,ByVal bSize As Byte) As Boolean
- Declare Function SetPortVal Lib "WinIo32.dll" (ByVal PortAddr As Integer,ByVal PortVal As Long,ByVal bSize As Byte) As Boolean
- Declare Function InitializeWinIo Lib "WinIo32.dll" () As Boolean
- Declare Function ShutdownWinIo Lib "WinIo32.dll" () As Boolean
- Declare Function InstallWinIoDriver Lib "WinIo32.dll" (ByVal DriverPath As String,ByVal Mode As Integer) As Boolean
- Declare Function RemoveWinIoDriver Lib "WinIo32.dll" () As Boolean
- Public Const KBC_KEY_CMD = &H64 '键盘命令端口
- Public Const KBC_KEY_DATA = &H60 '键盘数据端口
- Public Const VK_LButton = &H1 '鼠标左键
- Public Const VK_RButton = &H2 '鼠标右键
- Public Const VK_Cancel = &H3 'CANCEL键
- Public Const VK_MButton = &H4 '鼠标中键
- Public Const VK_Back = &H8 '退格键
- Public Const VK_Tab = &H9 'TAB键
- Public Const VK_Clear = &HC 'CLEAR健
- Public Const VK_RETURN = &HD '回车键
- Public Const VK_Shift = &H10 'SHIFT键
- Public Const VK_Control = &H11 'CTRL键
- Public Const VK_MENU = &H12 'MENU键
- Public Const VK_Pause = &H13 'PAUSE键
- Public Const VK_Capital = &H14 'CAPS LOCK 键
- Public Const VK_Escape = &H1B 'ESC键
- Public Const VK_Space = &H20 ' 空格键
- Public Const VK_PageUp = &H21 'Page Up 键
- Public Const VK_PageDown = &H22 'Page Down 键
- Public Const VK_End = &H23 'END键
- Public Const VK_Home = &H24 'HOME键
- Public Const VK_Left = &H25 '光标左键
- Public Const VK_Up = &H26 '光标上键
- Public Const VK_Right = &H27 '光标右键
- Public Const VK_Down = &H28 '光标下键
- Public Const VK_Select = &H29 'SELECT键
- Public Const VK_Print = &H2A 'Print Screen 键
- Public Const VK_Execute = &H2B 'EXECUTE键
- Public Const VK_Snapshot = &H2C 'SnapShot键
- Public Const VK_Insert = &H2D 'INSERT键
- Public Const VK_Delete = &H2E 'DELETE键
- Public Const VK_Help = &H2F 'HELP键
- Public Const VK_Numlock = &H90 'NUM LOCK 键
- Public Const VK_A = &H41 '字母A键
- Public Const VK_B = &H42 '字母B键
- Public Const VK_C = &H43 '字母C键
- Public Const VK_D = &H44 '字母D键
- Public Const VK_E = &H45 '字母E键
- Public Const VK_F = &H46 '字母F键
- Public Const VK_G = &H47 '字母G键
- Public Const VK_H = &H48 '字母H键
- Public Const VK_I = &H49 '字母I键
- Public Const VK_J = &H4A '字母J键
- Public Const VK_K = &H4B '字母K键
- Public Const VK_L = &H4C '字母L键
- Public Const VK_M = &H4D '字母M键
- Public Const VK_N = &H4E '字母N键
- Public Const VK_O = &H4F '字母O键
- Public Const VK_P = &H50 '字母P键
- Public Const VK_Q = &H51 '字母Q键
- Public Const VK_R = &H52 '字母R键
- Public Const VK_S = &H53 '字母S键
- Public Const VK_T = &H54 '字母T键
- Public Const VK_U = &H55 '字母U键
- Public Const VK_V = &H56 '字母V键
- Public Const VK_W = &H57 '字母W键
- Public Const VK_X = &H58 '字母X键
- Public Const VK_Y = &H59 '字母Y键
- Public Const VK_Z = &H5A '字母Z键
- Public Const VK_0 = &H30 '数字0键
- Public Const VK_1 = &H31 '数字1键
- Public Const VK_2 = &H32 '数字2键
- Public Const VK_3 = &H33 '数字3键
- Public Const VK_4 = &H34 '数字4键
- Public Const VK_5 = &H35 '数字5键
- Public Const VK_6 = &H36 '数字6键
- Public Const VK_7 = &H37 '数字7键
- Public Const VK_8 = &H38 '数字8键
- Public Const VK_9 = &H39 '数字9键
- Public Const VK_F1 = &H70 'F1功能键
- Public Const VK_F2 = &H71 'F2功能键
- Public Const VK_F3 = &H72 'F3功能键
- Public Const VK_F4 = &H73 'F4功能键
- Public Const VK_F5 = &H74 'F5功能键
- Public Const VK_F6 = &H75 'F6功能键
- Public Const VK_F7 = &H76 'F7功能键
- Public Const VK_F8 = &H77 'F8功能键
- Public Const VK_F9 = &H78 'F9功能键
- Public Const VK_F10 = &H79 'F10功能键
- Public Const VK_F11 = &H7A 'F11功能键
- Public Const VK_F12 = &H7B 'F12功能键
- Public Const VK_F13 = &H7C 'F13功能键
- Public Const VK_F14 = &H7D 'F14功能键
- Public Const VK_F15 = &H7E 'F15功能键
- Public Const VK_F16 = &H7F 'F16功能键
- Public Const VK_Numpad0 = &H60 '小键盘0键
- Public Const VK_Numpad1 = &H61 '小键盘1键
- Public Const VK_Numpad2 = &H62 '小键盘2键
- Public Const VK_Numpad3 = &H63 '小键盘3键
- Public Const VK_Numpad4 = &H64 '小键盘4键
- Public Const VK_Numpad5 = &H65 '小键盘5键
- Public Const VK_Numpad6 = &H66 '小键盘6键
- Public Const VK_Numpad7 = &H67 '小键盘7键
- Public Const VK_Numpad8 = &H68 '小键盘8键
- Public Const VK_Numpad9 = &H69 '小键盘9键
- Public Const VK_Multiply = &H6A '小键盘*键
- Public Const VK_Add = &H6B '小键盘+键
- Public Const VK_Separator = &H6C '小键盘回车键
- Public Const VK_Subtract = &H6D '小键盘-键
- Public Const VK_Decimal = &H6E '小键盘.键
- Public Const VK_Divide = &H6F '小键盘/键
- '**************************
- ' 等待键盘缓冲区为空
- '**************************
- Sub KBCWait4IBE()
- Dim dwVal As Long
- Do
- GetPortVal &H64,dwVal,1
- '这句表示从&H64端口读取一个字节并把读出的数据放到变量dwVal中
- 'GetPortVal函数的用法是GetPortVal 端口号,存放读出数据的变量,读入的长度
- Loop While (dwVal And &H2)
- End Sub
- '**************************************
- '
- '这个用来模拟按下键,参数vKeyCoad传入按键的虚拟码
- '
- '**************************************
- Sub MyKeyDown(ByVal vKeyCoad As Long) '
- Dim btScancode As Long
- btScancode = MapVirtualKey(vKeyCoad,0)
- KBCWait4IBE '发送数据前应该先等待键盘缓冲区为空
- SetPortVal KBC_KEY_CMD,&HD2,1 '发送键盘写入命令
- 'SetPortVal函数用于向端口写入数据,它的用法是SetPortVal 端口号,欲写入的数据,写入数据的长度
- KBCWait4IBE
- SetPortVal KBC_KEY_DATA,btScancode,1 '写入按键信息,按下键
- End Sub
- '**************************************
- '
- '这个用来模拟释放键,参数vKeyCoad传入按键的虚拟码
- '
- '**************************************
- Sub MyKeyUp(ByVal vKeyCoad As Long)
- '
- Dim btScancode As Long
- btScancode = MapVirtualKey(vKeyCoad,0)
- KBCWait4IBE '等待键盘缓冲区为空
- SetPortVal KBC_KEY_CMD,1 '发送键盘写入命令
- KBCWait4IBE
- SetPortVal KBC_KEY_DATA,(btScancode Or &H80),1 '写入按键信息,释放键
- End Sub
- '*********************************************************************
- ' 从扩展键转换到普通键,那么普通键的KeyDown事件应该发送两次。
- ' 也就是说,如果我想模拟先按下一个扩展键,再按下一个普通键,
- ' 那么就应该向端口发送 两次 该普通键被按下的信息
- ' MyKeyDownEx VK_LEFT '按下左方向键
- ' Sleep 200 '延时200毫秒
- ' MyKeyUpEx VK_LEFT '释放左方向键
- ' Sleep 500
- ' MyKeyDown VK_SPACE '按下空格键,注意要发送两次
- ' MyKeyDown VK_SPACE
- ' Sleep 200
- ' MyKeyUp VK_SPACE '释放空格键
- '**********************************************************************
- Sub MyKeyDownEx(ByVal vKeyCoad As Long) '模拟扩展键按下,参数vKeyCoad是扩展键的虚拟码
- Dim btScancode As Long
- btScancode = MapVirtualKey(vKeyCoad,1 '发送键盘写入命令
- KBCWait4IBE
- SetPortVal KBC_KEY_DATA,&HE0,1 '写入扩展键标志信息
- KBCWait4IBE '等待键盘缓冲区为空
- SetPortVal KBC_KEY_CMD,按下键
- End Sub
- '***********************************************
- '模拟扩展键弹起
- '**********************************************
- Sub MyKeyUpEx(ByVal vKeyCoad As Long)
- Dim btScancode As Long
- btScancode = MapVirtualKey(vKeyCoad,1 '写入扩展键标志信息
- KBCWait4IBE '等待键盘缓冲区为空
- SetPortVal KBC_KEY_CMD,1 '写入按键信息,释放键
- End Sub
- '----------------------------------------------------------------------------------------------------------------------------------------------------------
- Sub MySendKey(bkey As Long)
- '参数bkey传入要模拟按键的虚拟码即可模拟按下指定键
- Dim GInput(0 To 1) As GENERALINPUT
- Dim KInput As KEYBDINPUT
- KInput.wVk = bkey '你要模拟的按键
- KInput.dwFlags = 0 '按下键标志
- GInput(0).dwType = INPUT_KEYBOARD
- CopyMemory GInput(0).xi(0),KInput,Len(KInput) '这个函数用来把内存中KInput的数据复制到GInput
- KInput.wVk = bkey
- KInput.dwFlags = KEYEVENTF_KEYUP ' 释放按键
- GInput(1).dwType = INPUT_KEYBOARD ' 表示该消息为键盘消息
- CopyMemory GInput(1).xi(0),Len(KInput) '以上工作把按下键和释放键共2条键盘消息加入到GInput数据结构中
- SendInput 2,GInput(0),Len(GInput(0)) '把GInput中存放的消息插入到消息列队
- End Sub
- Function MakeKeyLparam(ByVal VirtualKey As Long,ByVal flag As Long) As Long
- Dim s As String
- Dim Firstbyte As String 'lparam参数的24-31位
- If flag = WM_KEYDOWN Then '如果是按下键
- Firstbyte = "00"
- Else
- Firstbyte = "C0" '如果是释放键
- End If
- Dim Scancode As Long
- '获得键的扫描码
- Scancode = MapVirtualKey(VirtualKey,0)
- Dim Secondbyte As String 'lparam参数的16-23位,即虚拟键扫描码
- Secondbyte = Right("00" & Hex(Scancode),2)
- s = Firstbyte & Secondbyte & "0001" '0001为lparam参数的0-15位,即发送次数和其它扩展信息
- MakeKeyLparam = Val("&H" & s)
- End Function
参考链接: