一步一步開發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,每次有新的一行加入的時候,都觸發該事件,然後調用相關的處理函數進行自定義繪製,可以註冊一個該事件,代碼見下         

   

   
voidCmcf6Dlg::OnNMCustomdrawList1(NMHDR *pNMHDR, LRESULT *pResult)
{
         //LPNMCUSTOMDRAWpNMCD = reinterpret_cast<LPNMCUSTOMDRAW>(pNMHDR);
         LPNMLVCUSTOMDRAWpNMCD = (LPNMLVCUSTOMDRAW)pNMHDR;
         *pResult= 0;
         //TODO: 在此添加控件通知處理程序代碼
         if(CDDS_PREPAINT==pNMCD->nmcd.dwDrawStage)
         {
                   *pResult= CDRF_NOTIFYITEMDRAW;
         }elseif(CDDS_ITEMPREPAINT ==pNMCD->nmcd.dwDrawStage){
                   COLORREFcrText;
                   charbuf[10];
                   memset(buf,0,10);
                   POSITION pos =this->m_localDataList.FindIndex(pNMCD->nmcd.dwItemSpec);
                   struct datapkt * local_data =(struct datapkt *)this->m_localDataList.GetAt(pos);
                   strcpy(buf,local_data->pktType);
 
                   if(strcmp(buf,"IPV6")==0)
                            crText= RGB(111,224,254);
                   elseif(strcmp(buf,"UDP")==0)
                            crText= RGB(194,195,252);                               
                   elseif(strcmp(buf,"TCP")==0)
                                     crText= RGB(230,230,230);
                   elseif(strcmp(buf,"ARP")==0)
                                     crText= RGB(226,238,227);
                   elseif(strcmp(buf,"ICMP")==0)
                                     crText= RGB(49,164,238);
                   elseif(strcmp(buf,"HTTP")==0)
                                     crText= RGB(238,232,180);
                   elseif(strcmp(buf,"ICMPv6")==0)
                                     crText= RGB(189,254,76);
 
                   pNMCD->clrTextBk=crText;
                   *pResult= CDRF_DODEFAULT;
         }
}

         首先通過下面這段代碼獲得新加入到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、將數據以字符形式顯示。代碼相信大家都看得懂,就不做過多解釋了。

void print_packet_hex(const u_char* pkt,intsize_pkt,CString *buf)
{
         inti=0,j = 0,rowcount;
          u_char ch;
 
          char tempbuf[256];
          memset(tempbuf,0,256);
 
         for(i= 0;i<size_pkt;i+=16)
         {
                   buf->AppendFormat(_T("%04x:  "),(u_int)i);
                   rowcount= (size_pkt-i) > 16 ? 16 : (size_pkt-i);                         
 
                   for(j = 0; j < rowcount; j++)              
                            buf->AppendFormat(_T("%02x  "),(u_int)pkt[i+j]);       
 
                   //不足16,用空格補足
                   if(rowcount<16)
                            for(j=rowcount;j<16;j++)
                                               buf->AppendFormat(_T("    "));  
 
 
                   for(j = 0; j < rowcount; j++)
                   {
            ch = pkt[i+j];
            ch = isprint(ch) ? ch : '.';
                             buf->AppendFormat(_T("%c"),ch);
                   }
 
                   buf->Append(_T("\r\n"));
                   if(rowcount<16)
                            return;
         }
}


至此,如何應用MFC寫一個sniffer就完整地結束了,未講清楚的,可直接參考代碼,這裏可進行代碼下載

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





發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章