qq 未读消息实现原理 自动发送QQ消息功能的原理及实现

一、QQ窗口分析

? ? 近来QQ尾巴病毒,在网络上很是流行,我也常常收到网友们发到来的带尾巴的消息。

国庆节闲来无事,就拿此病毒来消遣一下――写一个类似的自动发送QQ消息的小程序。

先让我们分析一下QQ尾巴的发作情况:当用户打开一个QQ消息发送窗口时,病毒会自动往消息文本框里输入文本,然后不等用户反应过来就发出去了。如果要实现这些功能必须获得QQ窗口“发送”按钮的句柄和文本框的句柄。

在进行程序编写之前需要使用Spy++ 软件对QQ窗口进行分析,以了解QQ窗口各个子窗口之间的关系。SSpy++ (SPYXX.EXE) 是一个基于 Win32(最新版本支持Win64) 的实用工具,它提供系统的进程、线程、窗口和窗口消息的图形视图。使用 Spy++ 可以执行下列操作: 显示系统对象(包括进程、线程和窗口)之间关系的图形树。 搜索指定的窗口、线程、进程或消息。 查看选定的窗口、线程、进程或消息的属性。 直接从视图中选择窗口、线程、进程或消息。 通过鼠标定位,使用查找程序工具选择窗口。 使用复杂的消息日志选择参数设置消息选项。?提示使用 Spy++ 时,在许多实例中都可以单击鼠标右键显示常用命令的弹出式菜单。命令是否可用取决于指针的位置。例如,如果在指向窗口视图中的某项时单击并且选定的窗口可见,则弹出式“突出显示”菜单项将导致选定窗口的边框闪烁,从而可以轻松地在屏幕上找到该窗口。

启动Spy++,并打开一个QQ窗口。在Spy++的“监视”菜单中选择“查找窗口”(如图1),就弹出如图2的窗口,然后选择“查找程序工具”,拖拉到QQ窗口的输入文本框上,

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

自动发送QQ消息功能的原理及实现_qq自动发信息

在图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;

}

else

hCurrentWindow=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序中指定窗口下的相同类型的窗口。如果指定窗口是最高端窗口,则该句柄标识了在指定窗口下的最高端窗口:如果指定窗口是顶层窗口,则该句柄标识了在指定窗口下的顶层窗口;如果指定窗口是子窗口,则句柄标识了在指定窗口下的同属窗口。

自动发送QQ消息功能的原理及实现_qq自动发信息

?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,则为所有窗口全匹配。

自动发送QQ消息功能的原理及实现_qq自动发信息

如果函数成功,返回值为具有指定类名和窗口名的窗口句柄。如果函数失败,返回值为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);

自动发送QQ消息功能的原理及实现_qq自动发信息

??? ::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)将上面所述的各种代码分别写进相应的函数。下面将有详尽的代码。

自动发送QQ消息功能的原理及实现_qq自动发信息

详尽代码如下:

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;

qq 未读消息实现原理 自动发送QQ消息功能的原理及实现

? CString SendText;

? hCurrentWindow=(CDialog*)GetWindow(GW_HWNDFIRST);

? while(hCurrentWindow!=NULL)

? {

????? hCurrentWindow->GetWindowText(WndText);

????? if((WndText.Find("聊天中")!=-1)||(WndText.Find("发送消息")!=-1))

????? {

????????? QQWnd=hCurrentWindow;

????????? break;

????? ?}

????? ?else

????????? ?hCurrentWindow=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消息的程序为主线,重点论述了三种子窗口获取的方法和两种发送消息的方法,希望给读者一点帮助。

  

爱华网本文地址 » http://www.aihuau.com/a/8105080103/331909.html

更多阅读

c++虚函数实现原理 虚函数实现原理

c++虚函数实现原理 - [c++]2011-09-15版权声明:转载时请以超链接形式标明文章原始出处和作者信息及本声明http://wanderer-zjhit.blogbus.com/logs/161830653.htmlFROM: http://pcedu.pconline.com.cn/empolder/gj/c/0503/574706_3.h

点读笔的原理_e路驿站 e cvt变速箱工作原理

点读笔的原理:一颗Sensor(红外感光)+MCU+OID算法+会反射红外光的特殊涂料印刷这是最基本的一个点读笔软硬件架构!!!点读笔的核心在于其OID算法。当前,市场上比较成熟的OID方案主要有sonix及sunplus。sonix的硬件架构包括MCU+SpeechIC+sen

声明:《qq 未读消息实现原理 自动发送QQ消息功能的原理及实现》为网友策划的情分享!如侵犯到您的合法权益请联系我们删除