最後一章是要將解析數據寫的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