昨天在群里看见一个小伙伴问一套键盘如何控制多台电脑?正好勾起以前学习Windows时候的乐趣,其实这个也做过,是我的一个朋友需要,实现原理也比较简单,大概就是通过键盘钩子钩住按键,通过Socket发送到其他电脑上,其他电脑开始模拟按键,鼠标也是一样,大概会用法到以下API。
啥是钩子
Windows中的窗口程序是基于消息机制,事件驱动的,根据不同的消息完成不同的功能,钩子就是拦截Windows的某些消息,在这个消息到达指定窗口前会拦截下来,我们可以从中获取我们想要的信息,可以加工改变这个消息,也可以不作处理继续传递下去,还可以强制结束消息的传递。
以前的键盘记录程序也应该用到这个技术,但也有可能更高深,因为现在大部分出名软件都有反钩子技术,如QQ,但TIM好像可以,无法使用普通的技术拦截QQ窗口中输入的密码,反之其他程序可以。
SetWindowsHookEx
最开始我们会通过这个函数来增加一个消息钩子,第一个参数就是安装的钩子类型,有非常多,如果键盘的话我们选择WH_KEYBOARD_LL。
HHOOK SetWindowsHookExA(
int idHook,
HOOKPROC lpfn,
HINSTANCE hmod,
DWORD dwThreadId
)
其余参数分别是 钩子子程的地址指针、应用程序实例的句柄、与安装的钩子子程相关联的线程的标识符, 如果为0,钩子子程与所有的线程关联,即为全局钩子。
CallNextHookEx
将挂钩信息传递到当前挂钩链中的下一个挂钩过程。
LRESULT CallNextHookEx(
HHOOK hhk,
int nCode,
WPARAM wParam,
LPARAM lParam
)
代码示例
Option Explicit
Private Declare Sub CopyMemory Lib "kernel32.dll" Alias "RtlMoveMemory" (ByRef Destination As Any, ByRef Source As Any, ByVal Length As Long)
Private Declare Function SetWindowsHookEx Lib "user32" Alias "SetWindowsHookExA" (ByVal idHook As Long, ByVal lpfn As Long, ByVal hmod As Long, ByVal dwThreadId As Long) As Long
Private Declare Function UnhookWindowsHookEx Lib "user32" (ByVal hHook As Long) As Long
Private Declare Function CallNextHookEx Lib "user32" (ByVal hHook As Long, ByVal nCode As Long, ByVal wParam As Long, lparam As Any) As Long
Private Const HC_ACTION = 0
Public Const WH_KEYBOARD_LL As Long = 13
Public Const WM_KEYDOWN As Long = &H100
Public Const WM_KEYUP As Long = &H101
Public Const WM_SYSKEYDOWN As Long = &H104
Public Const WM_SYSKEYUP As Long = &H105
Public Type KBDLLHOOKSTRUCT
vkCode As Long
scanCode As Long
flags As Long
time As Long
dwExtraInfo As Long
End Type
Public hHook As Long
Dim logTv As TextBox
Public Sub EnableHook()
Set logTv = Form1.Text1
If hHook = 0 Then
hHook = SetWindowsHookEx(WH_KEYBOARD_LL, AddressOf HookProc, App.hInstance, 0)
End If
End Sub
Public Sub FreeHook()
If hHook <> 0 Then
Call UnhookWindowsHookEx(hHook)
hHook = 0
End If
End Sub
Public Function HookProc(ByVal nCode As Long, ByVal wParam As Long, lparam As KBDLLHOOKSTRUCT) As Long
If wParam = WM_KEYDOWN Then
logTv.Text = logTv.Text & vbCrLf & "键盘按下 " & Chr(lparam.vkCode)
ElseIf wParam = WM_KEYUP Then
logTv.Text = logTv.Text & vbCrLf & "键盘抬起 " & Chr(lparam.vkCode)
End If
logTv.SelLength = Len(logTv.Text)
HookProc = CallNextHookEx(hHook, nCode, wParam, lparam)
End Function
剩下的就是通过Socket发送到其他电脑上,使用keybd_event来模拟键盘按下、抬起。但是这个函数现在貌似被SendInput取代了。SendInput并没有研究过。
void keybd_event(
BYTE bVk,
BYTE bScan,
DWORD dwFlags,
ULONG_PTR dwExtraInfo
);