一步一步开发sniffer(Winpcap+MFC)(六)千呼万唤始出来,不抱琵琶也露面——将解析数据写到GUI上

最后一章是要将解析数据写的GUI上,先来回顾一下GUI长什么样,这样就对要在界面上写什么数据心中有数了,如下这两图:

 


可以看出,要写在GUI上的数据主要有五个部分:

1、  参数设置:网卡接口、过滤项

2、  数据包捕获列表,显示数据包简要信息

3、  树形目录,显示被选中的数据包头详细信息

4、  文本框,显示被选中的数据包十六进制信息

5、  统计信息:各类包的数量

限于篇幅接下来不会对所有信息是怎么放、每个控件怎么操作一一讲解了。首先会简单讲解一下是如何将数据放到界面上的;同时再对一些要点:第2点信息中如何根据数据包类型显示不同颜色背景,第4点信息中如何将数据包内容以格式化的方式显示出来做一下讲解。

一、控件写数据的基本操作

由于我们选择的是对话框的形式的界面,所以主界面只有一个,放置在主界面上的各个控件都可以通过主界面的this指针调用,并设置控件的值,例如:

          this->m_listCtrl.SetItemText(nItem,2,buf);

其中m_listCtrl是放置于主界面上的一个列表控件,至于参数是什么意思查MSDN吧。各种控件上的数据也就基本通过这样的方式调用

 

程序中我们新开了一个线程来处理数据,线程中每收到一个数据包都需要更新一下界面,这样就可以实时看到捕获的数据及统计信息了,这需要我们把主界面的this指针传递给线程,如下:

         m_ThreadHandle=CreateThread(NULL,0,lixsinff_CapThread,this,0,threadCap);

线程处理函数原型如下:

         DWORD WINAPI lixsinff_CapThread(LPVOID lpParameter);

这里的lpParameter就是刚刚传递进来的this指针了,在函数中使用如下:

         Cmcf6Dlg*pthis = (Cmcf6Dlg*) lpParameter;

其他的使用就跟前面一样了。

        

有时候需要根据事件来显示数据,那么控件的事件怎么添加呢,一个简单的办法就是打开资源视图,选择某一控件,再点击“闪电”形的按钮,就可以看到IDE已经早就为控件设置好各种事件了,你只需要选择某一事件,并增加自定义函数就行了。如下图

                  

二、两个要点

下面两个要点是我在显示数据的时候遇到的实际困难,因为其他的数据都是直接将数据写到控件里就完事了,而这里则要先做一些预处理,将这个贴出来节省大家时间。

2.1根据不同协议显示不同颜色

从下面这幅图可以看到,List控件有一个事件是NM_CUSTOMDRAW,每次有新的一行加入的时候,都触发该事件,然后调用相关的处理函数进行自定义绘制,可以注册一个该事件,代码见下         

   

[cpp]  view plain copy
  1.      
  2. voidCmcf6Dlg::OnNMCustomdrawList1(NMHDR *pNMHDR, LRESULT *pResult)  
  3. {  
  4.          //LPNMCUSTOMDRAWpNMCD = reinterpret_cast(pNMHDR);  
  5.          LPNMLVCUSTOMDRAWpNMCD = (LPNMLVCUSTOMDRAW)pNMHDR;  
  6.          *pResult= 0;  
  7.          //TODO: 在此添加控件通知处理程序代码  
  8.          if(CDDS_PREPAINT==pNMCD->nmcd.dwDrawStage)  
  9.          {  
  10.                    *pResult= CDRF_NOTIFYITEMDRAW;  
  11.          }elseif(CDDS_ITEMPREPAINT ==pNMCD->nmcd.dwDrawStage){  
  12.                    COLORREFcrText;  
  13.                    charbuf[10];  
  14.                    memset(buf,0,10);  
  15.                    POSITION pos =this->m_localDataList.FindIndex(pNMCD->nmcd.dwItemSpec);  
  16.                    struct datapkt * local_data =(struct datapkt *)this->m_localDataList.GetAt(pos);  
  17.                    strcpy(buf,local_data->pktType);  
  18.    
  19.                    if(strcmp(buf,"IPV6")==0)  
  20.                             crText= RGB(111,224,254);  
  21.                    elseif(strcmp(buf,"UDP")==0)  
  22.                             crText= RGB(194,195,252);                                 
  23.                    elseif(strcmp(buf,"TCP")==0)  
  24.                                      crText= RGB(230,230,230);  
  25.                    elseif(strcmp(buf,"ARP")==0)  
  26.                                      crText= RGB(226,238,227);  
  27.                    elseif(strcmp(buf,"ICMP")==0)  
  28.                                      crText= RGB(49,164,238);  
  29.                    elseif(strcmp(buf,"HTTP")==0)  
  30.                                      crText= RGB(238,232,180);  
  31.                    elseif(strcmp(buf,"ICMPv6")==0)  
  32.                                      crText= RGB(189,254,76);  
  33.    
  34.                    pNMCD->clrTextBk=crText;  
  35.                    *pResult= CDRF_DODEFAULT;  
  36.          }  
  37. }  

         首先通过下面这段代码获得新加入到List列表中的数据位置

                    POSITION pos = this->m_localDataList.FindIndex(pNMCD->nmcd.dwItemSpec);

         然后通过下面代码获得新加入行中存储的数据

                   structdatapkt * local_data = (struct datapkt *)this->m_localDataList.GetAt(pos);

         最后根据数据中对应的协议设置不同的显示颜色。这样,一个界面友好的列表就设置好了。 

 2.2对数据格式化显示

          主要通过下面这个函数实现,下面这个函数主要做了两件事:1、将数据是16进制的形式显示;2、将数据以字符形式显示。代码相信大家都看得懂,就不做过多解释了。

[cpp]  view plain copy
  1. void print_packet_hex(const u_char* pkt,intsize_pkt,CString *buf)  
  2. {  
  3.          inti=0,j = 0,rowcount;  
  4.           u_char ch;  
  5.    
  6.           char tempbuf[256];  
  7.           memset(tempbuf,0,256);  
  8.    
  9.          for(i= 0;i
  10.          {  
  11.                    buf->AppendFormat(_T("%04x:  "),(u_int)i);  
  12.                    rowcount= (size_pkt-i) > 16 ? 16 : (size_pkt-i);                           
  13.    
  14.                    for(j = 0; j < rowcount; j++)                
  15.                             buf->AppendFormat(_T("%02x  "),(u_int)pkt[i+j]);         
  16.    
  17.                    //不足16,用空格补足  
  18.                    if(rowcount<16)  
  19.                             for(j=rowcount;j<16;j++)  
  20.                                                buf->AppendFormat(_T("    "));    
  21.    
  22.    
  23.                    for(j = 0; j < rowcount; j++)  
  24.                    {  
  25.             ch = pkt[i+j];  
  26.             ch = isprint(ch) ? ch : '.';  
  27.                              buf->AppendFormat(_T("%c"),ch);  
  28.                    }  
  29.    
  30.                    buf->Append(_T("\r\n"));  
  31.                    if(rowcount<16)  
  32.                             return;  
  33.          }  
  34. }  


至此,如何应用MFC写一个sniffer就完整地结束了,未讲清楚的,可直接参考代码,这里可进行代码下载

http://download.csdn.net/download/litingli/4110529


你可能感兴趣的:(sinffer)