一、QQ窗口分析

近来QQ尾巴病毒,在网络上很是流行,我也常常收到网友们发到来的带尾巴的消息。国庆节闲来无事,就拿此病毒来消遣一下——写一个类似的自动发送QQ消息的小程序。
先让我们分析一下QQ尾巴的发作情况:当用户打开一个QQ消息发送窗口时,病毒会自动往消息文本框里输入文本,然后不等用户反应过来就发出去了。如果要实现这些功能必须获得QQ窗口“发送”按钮的句柄和文本框的句柄。
在进行程序编写之前需要使用Spy++ 软件对QQ窗口进行分析,以了解QQ窗口各个子窗口之间的关系。SSpy++ (SPYXX.EXE) 是一个基于 Win32(最新版本支持Win64) 的实用工具,它提供系统的进程、线程、窗口和窗口消息的图形视图。使用 Spy++ 可以执行下列操作: 显示系统对象(包括进程、线程和窗口)之间关系的图形树。 搜索指定的窗口、线程、进程或消息。 查看选定的窗口、线程、进程或消息的属性。 直接从视图中选择窗口、线程、进程或消息。 通过鼠标定位,使用查找程序工具选择窗口。 使用复杂的消息日志选择参数设置消息选项。 提示使用 Spy++ 时,在许多实例中都可以单击鼠标右键显示常用命令的弹出式菜单。命令是否可用取决于指针的位置。例如,如果在指向窗口视图中的某项时单击并且选定的窗口可见,则弹出式“突出显示”菜单项将导致选定窗口的边框闪烁,从而可以轻松地在屏幕上找到该窗口。
启动Spy++,并打开一个QQ窗口。在Spy++的“监视”菜单中选择“查找窗口”(如图1),就弹出如图2的窗口,然后选择“查找程序工具”,拖拉到QQ窗口的输入文本框上,

单击确定,就弹出如图3的窗口。

在图3这个窗口中,我们可以对当前窗口的类别、父窗口和子窗口的继承关系等有关该窗口的信息。经分析,输入文本框是QQ窗口的第4个子窗口的第23个子窗口的第1个子窗口,这对我们程序的编写十分重要。采用同样的步骤,对“发送”按钮进行分析,得到:“发送”是QQ窗口的一个子窗口。在本文中为了示范作用,我们采用多种不同的方式获得子窗口。本程序是在VC++2003开发环境下编写的,可以正常运行。

二、QQ窗口句柄的获取

QQ窗口有两种,一种是消息模式,在这种情况下,窗口标题含有“发送消息”字样;一种是聊天模式,窗口标题含有“聊天中”字样。这些文字将成为我们寻找QQ窗口的线索。下面是获得QQ窗口的代码:

CWnd *hCurrentWindow;
CWnd *QQWnd;
CString WndText;
CString SendText;
hCurrentWindow=(CDialog* )GetWindow(GW_HWNDFIRST);
while(hCurrentWindow!=NULL)
{hCurrentWindow->GetWindowText(WndText);if((WndText.Find("聊天中")!=-1)||(WndText.Find("发送消息")!=-1)){QQWnd=hCurrentWindow;break;}elsehCurrentWindow=hCurrentWindow->GetWindow(GW_HWNDNEXT);
}

在对代码进行解释之间,先对GetWindow(UNIT nCmd)进行简单的介绍。该函数返回与窗口有特定关系(如Z序或所有者)的窗口句柄。参数nCmd:说明指定窗口与要获得句柄的窗口之间的关系。该参数值可以是下列之一:

  • GW_CHILD:如果指定窗口是父窗口,则获得的是在Z序顶端的子窗口的句柄,否则为NULL。函数仅检查指定父窗口的子窗口,不检查继承窗口。
  • GW_ENABLEDPOUP:(WindowsNT 5.0)返回的句柄标识了属于指定窗口的处于使能状态弹出式窗口(检索使用第一个由GW_HWNDNEXT 查找到的满足前述条件的窗口);如果无使能窗口,则获得的句柄与指定窗口相同。
  • GW_HWNDFIRST:返回的句柄标识了在Z序最高端的相同类型的窗口。如果指定窗口是最高端窗口,则该句柄标识了在Z序最高端的最高端窗口;如果指定窗口是顶层窗口,则该句柄标识了在Z序最高端的顶层窗口:如果指定窗口是子窗口,则句柄标识了在Z序最高端的同属窗口。
  • GW_HWNDLAST:返回的句柄标识了在Z序最低端的相同类型的窗口。如果指定窗口是最高端窗口,则该柄标识了在Z序最低端的最高端窗口:如果指定窗口是顶层窗口,则该句柄标识了在Z序最低端的顶层窗口;如果指定窗口是子窗口,则句柄标识了在Z序最低端的同属窗口。
  • GW_HWNDNEXT:返回的句柄标识了在Z序中指定窗口下的相同类型的窗口。如果指定窗口是最高端窗口,则该句柄标识了在指定窗口下的最高端窗口:如果指定窗口是顶层窗口,则该句柄标识了在指定窗口下的顶层窗口;如果指定窗口是子窗口,则句柄标识了在指定窗口下的同属窗口。
    
  •  GW HWNDPREV:返回的句柄标识了在Z序中指定窗口上的相同类型的窗口。如果指定窗口是最高端窗口,则该句柄标识了在指定窗口上的最高端窗口;如果指定窗口是顶层窗口,则该句柄标识了在指定窗口上的顶层窗口;如果指定窗口是子窗口,则句柄标识了在指定窗口上的同属窗口。
    
  •   GW_OWNER:返回的句柄标识了指定窗口的所有者窗口(如果存在)。
    

如果函数成功,返回值为窗口句柄;如果与指定窗口有特定关系的窗口不存在,则返回值为NULL。

在本段代码中我们用到了GW_HWNDFIRST和GW_HWNDNEXT这两个参数。该代码的思路是:首先获得最高端的窗口,然后获得其文本,判断其文本中是否包含“聊天中”或者“发送消息”,若包含,则找到QQ窗口;否则,转到下一个窗口。

三、为文本框设置文本

在获得了QQ窗口的句柄之后,我们就可以依据前面的分析,进一步找到输入文本框的句柄,对文本进行设置。
以下为获得QQ窗口输入文本框句柄的代码:

HWND CQQTailDlg:: MyChildWnd(HWNDhwnd,int num)//查找第num个子窗口,hwnd
//为父窗口
{HWND ChildWnd=0;for(int i=0;i<num;i++){ChildWnd = ::FindWindowEx(hwnd,ChildWnd,NULL,NULL);}
return ChildWnd;
}void CQQTailDlg::FindQQTextWnd(HWND hwnd) //查找输入文本框句柄
{HWND TempWnd;TempWnd=MyChildWnd(hwnd,4);TempWnd=MyChildWnd(TempWnd,23);TempWnd=MyChildWnd(TempWnd,1);TextWnd=TempWnd;
}

在本段代码里,查找子窗口,没有用上面提到的GetWindow()函数,而是FindWindowEx(HWND hwndParent,HWND hwndChildAfter,LPCTSTR lpszClass,LPCTSTR lpszWindow)。该函数获得一个窗口的句柄,该窗口的类名和窗口名与给定的字符串相匹配。这个函数查找子窗口,从排在给定的子窗口后面的下一个子窗口开始,在查找时不区分大小写。下面对其参数进行介绍

  • hwndParent:要查找子窗口的父窗口句柄。如果hwnjParent为NULL,则函数以桌面窗口为父窗口,查找桌面窗口的所有子窗口。
  • hwndChildAfter:子窗口句柄。查找从在Z序中的下一个子窗口开始。子窗口必须为hwndPareRt窗口的直接子窗口而非后代窗口。如果HwndChildAfter为NULL,查找从hwndParent的第一个子窗口开始。如果hwndParent 和 hwndChildAfter同时为NULL,则函数查找所有的顶层窗口及消息窗口。
  • lpszClass:指向一个指定了类名的空结束字符串,或一个标识类名字符串的成员的指针。如果该参数为一个成员,则它必须为前次调用theGlobaIAddAtom函数产生的全局成员。该成员为16位,必须位于lpClassName的低16位,高位必须为0。
  • lpszWindow:指向一个指定了窗口名(窗口标题)的空结束字符串。如果该参数为 NULL,则为所有窗口全匹配。

如果函数成功,返回值为具有指定类名和窗口名的窗口句柄。如果函数失败,返回值为NULL。
有前面的分析可知:输入文本框是QQ窗口的第4个子窗口的第23个子窗口的第1个子窗口,所以在FindQQTextWnd函数里出现了以下代码:

TempWnd=MyChildWnd(hwnd,4);
TempWnd=MyChildWnd(TempWnd,23);
TempWnd=MyChildWnd(TempWnd,1);

在获得了输入文本框句柄之后,就可以在文本框里设置你想发送的文本了。一般情况下可以向文本框发送WM_SETTEXT消息来实现,但是腾讯公司使用了一些技术,对文本框屏蔽了WM_SETTEXT消息。所以我们必须寻找其他的途径。功夫不负有心人,经过反复测试发现,WM_CHAR消息没有被腾讯公司屏蔽。因此,可以使用这个消息把字符发送到文本框。以下为设置文本代码:

void CQQTailDlg::SetTextWndText(HWNDhwnd,LPSTR pstr)//设置文本
{int len=::strlen(pstr);for(int i=0;i<len;i++){::PostMessage(hwnd,WM_CHAR,pstr[i],0);}
}

这里用到了一个十分关键的函数PostMessage(HWND hWnd,UINT Msg,WPARAM wParam,LPARAM lParam)。该函数将一个消息放入(寄送)到与指定窗口创建的线程相联系消息队列里,不等待线程处理消息就返回。下面对其参数进行解释:

  • hWnd:其窗口程序接收消息的窗口的句柄。
  • Msg:指定被寄送的消息。
  • wParam:指定附加的消息特定的信息。
  • IParam:指定附加的消息特定的信息。

如果函数调用成功,返回非零值;如果函数调用失败,返回值是零。
在此我们不得不提到另外一个类似的函数SendMessage,在后面我们对其有详尽的介绍。PostMessage 和SendMessage的区别主要在于是否等待其他程序消息处理。PostMessage只是把消息放入队列,不等待线程处理消息完成就返回,然后继续执行;SendMessage把消息直接发送到窗口,并调用此窗口的相应消息处理函数,等消息处理函数结束后才返回。这两个函数的返回值也不同,PostMessage的返回值表示PostMessage函数执行是否正确,而SendMessage的返回值表示其他程序处理消息后的返回值。

至此我们就完成了向输入文本框添加文本的工作,下一步就是如何将文本自动发送出去。

四、文本的自动发送

要想实现文本的自动发送,首先必须获得“发送”按钮的句柄,然后向其发送左单击消息和弹起消息就可以了。

下面是获得“发送”按钮句柄的代码:

EnumChildWindows(QQWnd->m_hWnd,(WNDENUMPROC)EnumChildProc,0);

以及该函数调用的回调函数EnumChildProc:

BOOL CALLBACKEnumChildProc(HWND hwnd, LPARAM lParam)
{LPTSTR pstr;pstr= new TCHAR[100];int len=GetWindowTextLength(hwnd);::GetWindowText(hwnd,pstr,len+1);char *p;p=strstr(pstr,"发送");if(p&&len>1){SendWnd=hwnd;}return TRUE;
}

在此段代码中我们使用了另外一种方式获得子窗口的句柄——枚举子窗口,使用了EnumChildWindows(HWND hWndParent,WNDENUMPROC lpEnumFunc,LPARAMlParam)函数。该函数可以枚举一个父窗口的所有子窗口。下面对其参数进行解释:

  • hWndParent:父窗口句柄
  • lpEnumFunc: 回调函数的地址
  • lParam:自已定义的参数

该函数直到最个一个子窗口被枚举或回调函数返回一个false,否则将一直枚举下去。

EnumChildProc是一个回调函数,负责对每一个子窗口的操作。注意:此回调函数要么是类的静态函数,要么就是一个全局的函数。在本程序中将其设为全局函数。通过代码我们可以知道,在回调函数中,获取每一个子窗口的文本,判断其是否包含“发送”,若包含,则认为该子窗口为“发送”按钮。
获取按钮句柄之后,就可以很方便的向该窗口发送消息,代码如下:

::SendMessage(SendWnd,WM_LBUTTONDOWN,MK_LBUTTON,0);
::SendMessage(SendWnd,WM_LBUTTONUP,0,0);

这里我们用到了我们前面提到的SendMessage(HWND hWnd,UINT Msg,WPARAM wParam,LPARAM IParam),该函数将指定的消息发送到一个或多个窗口。下面对其参数进行解释:

  • hWnd:其窗口程序将接收消息的窗口的句柄。
  • Msg:指定被发送的消息。
  • wParam:指定附加的消息指定信息。
  • IParam:指定附加的消息指定信息。

该函数的返回值是指定消息处理的结果,依赖于所发送的消息。

至此我们就完成了文本的自动发送。

五、程序实现步骤

本程序是在VC++2005开发平台上开发而成的,是一个基于对话框的MFC应用程序。程序实现的具体步骤如下:

(1)在VC++ 2005下新建一个名为QQTail的解决方案,在应用程序类型中,选择基于对话框。

(2)使用对话框编辑器,将对话框设计为如图4所示的窗口。

(3)为“开始”、“停止”和“关闭”按钮添加消息处理函数,为两个文本框分别添加变量。

(4)将上面所述的各种代码分别写进相应的函数。下面将有详尽的代码。

详尽代码如下:

voidCQQTailDlg::OnBnClickedOk()//“开始”按钮代码
{this->UpdateData(true);pstr= new TCHAR[100];m_text.GetWindowText(pstr,100);m_time=m_time*1000;this->SetTimer(1,m_time,NULL);//设置计时器
}voidCQQTailDlg::OnBnClickedPause()//“停止”按钮代码
{this->KillTimer(1);//删除计时器
}voidCQQTailDlg::QQTailStart()//该程序的核心函数,用于启动各个相关函数
{CString WndText;CString SendText;hCurrentWindow=(CDialog*)GetWindow(GW_HWNDFIRST);while(hCurrentWindow!=NULL){hCurrentWindow->GetWindowText(WndText);if((WndText.Find("聊天中")!=-1)||(WndText.Find("发送消息")!=-1)){QQWnd=hCurrentWindow;break;}elsehCurrentWindow=hCurrentWindow->GetWindow(GW_HWNDNEXT);}EnumChildWindows(QQWnd->m_hWnd,(WNDENUMPROC)EnumChildProc,0);FindQQTextWnd(QQWnd->m_hWnd);//获得文本框句柄SetTextWndText(TextWnd,pstr);//设置文本::SendMessage(SendWnd,WM_LBUTTONDOWN,MK_LBUTTON,0);::SendMessage(SendWnd,WM_LBUTTONUP,0,0);
}voidCQQTailDlg::OnTimer(UINT nIDEvent)//计时器处理函数
{if(nIDEvent==1)this->QQTailStart();CDialog::OnTimer(nIDEvent);
}

其它相关函数已在前面进行了说明,在此不在赘述。

下面为程序的运行结果:

图5:运行结果

图5的(1)为程序的运行界面,设置间隔时间为1秒,发送文本为star;(2)为对当前打开的QQ窗口的作用效果,我们可以看出,QQ确实每隔1秒就发送star一次,达到了预定的目标。

六、总结

本文以实现一个自动发送QQ消息的程序为主线,重点论述了三种子窗口获取的方法和两种发送消息的方法,希望给读者一点帮助。

自动发送QQ消息功能的原理及实现相关推荐

  1. 用python自动发送qq消息 可选择发送内容与次数

    python初学者,今天来试一下用python实现自动发送qq消息,实现自动化刷屏 只需要输入你要发送的内容.要发送的好友名称以及发送的次数,就可以实现了,效果如下 注意:聊天框必须只开这一个窗口,否 ...

  2. Java手机通讯录并实现自动发送QQ消息及单人视频聊天窗口

    目录 Java手机通讯录并实现自动发送QQ消息及单人视频聊天窗口 1. 原始问题描述 2. 实现效果​             ​            ​              ​ 3.部分源码 ...

  3. python自动发送qq消息_自动给qq好友发消息

    该楼层疑似违规已被系统折叠 隐藏此楼查看此楼 最近突然想做个自动发送qq消息的东西,然后上网搜了一下实现方法,找到了几篇用python实现的帖子,就自己试了试(原来只是简单了解过python,好多地方 ...

  4. python实现自动发送qq消息

    太好玩了,刚开始的时候一不留神发群里了,肾上腺素激增,幸好那个群禁言! 下载相关库包: pip install pyautogui Mac版: import pyautogui as gui gui. ...

  5. Python 自动发送QQ端口消息 —— 2022/2/10

    自动发送QQ消息 pip install pywin32 -i http://pypi.douban.com/simple/ --trusted-host pypi.douban.com import ...

  6. 【C#】QQ消息自动发送代码

    1.准备Windows API,是用C#开发的,所以要准备C#封装的Windows API.可以到以下地址下载: C#版封装的Windows API,简体版+增加版,源码 http://bmpj.ne ...

  7. 使用python发送qq消息

    以前看到网上一些小程序,在处理完事物后会自动发送qq消息,但是一直搞不懂是说明原理.也在网上找过一些python登陆qq发送消息的文字,但是都太复杂了.今天偶然看到一篇文章,是用python调用win ...

  8. python回复qq消息_自动给qq好友发消息

    该楼层疑似违规已被系统折叠 隐藏此楼查看此楼 最近突然想做个自动发送qq消息的东西,然后上网搜了一下实现方法,找到了几篇用python实现的帖子,就自己试了试(原来只是简单了解过python,好多地方 ...

  9. android qq功能实现原理,Android QQ、微信聊天消息界面设计原理与实现

     Android QQ.微信聊天消息界面设计原理与实现 原理:Android平台上,典型的以腾讯的QQ.微信这些聊天消息界面通常可以采用ListView设计与实现,需要使用ListView 适配器 ...

最新文章

  1. layui轮播图切换会有跳动_Layui中轮播图切换函数说明
  2. Android模拟器体验有感
  3. KVC 与 KVO 理解
  4. oracle 字段对错,oracle 两表之间字段赋值错误解析
  5. 量化指标公式源码_精选指标:五行八卦图-五行量化指标公式——附源码
  6. vs201中添加splashScreen
  7. hackthon java_Hackathon 参赛指南——如何愉快地参加一场 Hackathon
  8. 智能蓝牙音箱方案的四大问题
  9. 从招股书看蚂蚁集团的技术底色
  10. 爬虫技术(01)神箭手爬虫初学案例解读
  11. EasyExcel删除模版Sheet页
  12. 操作系统实验指导书(完整版)
  13. 如何解决LabView的Active X容器中无Animation GIF Control问题
  14. vue - 下拉列表
  15. 极简权限认证必须掌握【代码+原理+建议收藏】
  16. 细说final的的四种用法-----修饰类,修饰方法,常量,修饰参数 及内部类与final
  17. ArcGIS空间分析实验数据(汤国安版)
  18. 音视频开发系列(19)玩转 WebRTC 安全通信:一文读懂 DTLS 协议
  19. 阿里字体图标使用方法
  20. 江苏计算机等级考试vfp,江苏计算机等级考试二级vfp考试简介.doc

热门文章

  1. 舍弃Kong和Nginx,Apache APISIX 在趣链科技 BaaS 平台的落地实践
  2. 产品经理PUA老板话术大赏
  3. 温商机器人企业_“2018温州市百强企业”揭晓
  4. 怎么在word中划横线
  5. cad批量交点打断 lisp_晓东CAD家园-论坛-A/VLISP-批量交点打断-各位有批量交点打断!!各自塞下 总有个你觉得很好 - Powered by Discuz!...
  6. 反馈顶点集问题(1)
  7. opencv系列之基于NVIDIA显卡的opencv-python硬解方案
  8. 吊打面试官系列之--吃透Spring ioc 和 aop (中)
  9. allero过孔盖油PCB文件设置
  10. ASP.NET MVC +Layui 实现图片上传功能