添加列表控件元素时MFC应用程序卡住[关闭]
Posted
技术标签:
【中文标题】添加列表控件元素时MFC应用程序卡住[关闭]【英文标题】:MFC Application getting stuck when adding list control elements [closed] 【发布时间】:2015-10-29 10:38:37 【问题描述】:MFC 应用程序在向列表控件添加元素时卡住,无法单击任何其他按钮,甚至无法在嗅探网络数据包时关闭按钮。
整个代码如下所示:
// SnifferSampleDlg.cpp : implementation file
//
#include "stdafx.h"
#include "SnifferSample.h"
#include "SnifferSampleDlg.h"
#include "afxdialogex.h"
#include <Windows.h>
#include <WinSock2.h>
#include <mstcpip.h>
#ifdef _DEBUG
#define new DEBUG_NEW
#endif
#pragma comment(lib,"ws2_32.lib") //For winsock
// CSnifferSampleDlg dialog
//typedef struct ip_hdr
//
// unsigned char ip_header_len:4; // 4-bit header length (in 32-bit words) normally=5 (Means 20 Bytes`enter code here` may be 24 also)
// unsigned char ip_version :4; // 4-bit IPv4 version
// unsigned char ip_tos; // IP type of service
// unsigned short ip_total_length; // Total length
// unsigned short ip_id; // Unique identifier
//
// unsigned char ip_frag_offset :5; // Fragment offset field
//
// unsigned char ip_more_fragment :1;
// unsigned char ip_dont_fragment :1;
// unsigned char ip_reserved_zero :1;
//
// unsigned char ip_frag_offset1; //fragment offset
//
// unsigned char ip_ttl; // Time to live
// unsigned char ip_protocol; // Protocol(TCP,UDP etc)
// unsigned short ip_checksum; // IP checksum
// unsigned int ip_srcaddr; // Source address
// unsigned int ip_destaddr; //destination address
// IPV4_HDR;
typedef struct tcp_header
unsigned short source_port; // source port
unsigned short dest_port; // destination port
unsigned int sequence; // sequence number - 32 bits
unsigned int acknowledge; // acknowledgement number - 32 bits
unsigned char ns :1; //Nonce Sum Flag Added in RFC 3540.
unsigned char reserved_part1:3; //according to rfc
unsigned char data_offset:4; /*The number of 32-bit words in the TCP header.
This indicates where the data begins.
The length of the TCP header is always a multiple
of 32 bits.*/
unsigned char fin :1; //Finish Flag
unsigned char syn :1; //Synchronise Flag
unsigned char rst :1; //Reset Flag
unsigned char psh :1; //Push Flag
unsigned char ack :1; //Acknowledgement Flag
unsigned char urg :1; //Urgent Flag
unsigned char ecn :1; //ECN-Echo Flag
unsigned char cwr :1; //Congestion Window Reduced Flag
////////////////////////////////
unsigned short window; // window
unsigned short checksum; // checksum
unsigned short urgent_pointer; // urgent pointer
TCP_HDR;
int total = 0,icmp = 0, igmp = 0,tcp = 0 ,udp = 0 ,others = 0;
CSnifferSampleDlg::CSnifferSampleDlg(CWnd* pParent /*=NULL*/)
: CDialogEx(CSnifferSampleDlg::IDD, pParent)
m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
void CSnifferSampleDlg::DoDataExchange(CDataExchange* pDX)
CDialogEx::DoDataExchange(pDX);
DDX_Control(pDX, IDC_LIST1, m_listCtrl);
BEGIN_MESSAGE_MAP(CSnifferSampleDlg, CDialogEx)
ON_WM_PAINT()
ON_WM_QUERYDRAGICON()
ON_BN_CLICKED(IDC_BUTTON1, &CSnifferSampleDlg::OnBnClickedButton1)
END_MESSAGE_MAP()
// CSnifferSampleDlg message handlers
static void AddData(CListCtrl &ctrl, int row, int col, LPWSTR str)
LVITEM lv;
lv.iItem = row;
lv.iSubItem = col;
lv.pszText = str;
lv.mask = LVIF_TEXT;
if(col == 0)
ctrl.InsertItem(0,str);
/*ctrl.RedrawItems( 0, tcp);*/
else
ctrl.SetItem(&lv);
BOOL CSnifferSampleDlg::OnInitDialog()
CDialogEx::OnInitDialog();
// Set the icon for this dialog. The framework does this automatically
// when the application's main window is not a dialog
SetIcon(m_hIcon, TRUE); // Set big icon
SetIcon(m_hIcon, FALSE); // Set small icon
// TODO: Add extra initialization here
m_listCtrl.InsertColumn(0, L"Source");
m_listCtrl.SetColumnWidth(0, 100);
m_listCtrl.InsertColumn(1,L"Destination");
m_listCtrl.SetColumnWidth(1, 100);
m_listCtrl.InsertColumn(2, L"Protocol");
m_listCtrl.SetColumnWidth(2, 90);
m_listCtrl.SendMessage(LVM_SETEXTENDEDLISTVIEWSTYLE, 0,
LVS_EX_FULLROWSELECT);
return TRUE; // return TRUE unless you set the focus to a control
// If you add a minimize button to your dialog, you will need the code below
// to draw the icon. For MFC applications using the document/view model,
// this is automatically done for you by the framework.
void CSnifferSampleDlg::OnPaint()
if (IsIconic())
CPaintDC dc(this); // device context for painting
SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0);
// Center icon in client rectangle
int cxIcon = GetSystemMetrics(SM_CXICON);
int cyIcon = GetSystemMetrics(SM_CYICON);
CRect rect;
GetClientRect(&rect);
int x = (rect.Width() - cxIcon + 1) / 2;
int y = (rect.Height() - cyIcon + 1) / 2;
// Draw the icon
dc.DrawIcon(x, y, m_hIcon);
else
CDialogEx::OnPaint();
// The system calls this function to obtain the cursor to display while the user drags
// the minimized window.
HCURSOR CSnifferSampleDlg::OnQueryDragIcon()
return static_cast<HCURSOR>(m_hIcon);
int CSnifferSampleDlg::Startbutton()
SOCKET ListenSocket;
struct sockaddr_in saServer;
hostent* localHost;
char* localIP;
WSADATA wsaData;
int iResult;
tcp=0;
//Initialising Winsock....
iResult = WSAStartup(MAKEWORD(2,2), &wsaData);
if (iResult != 0)
AfxMessageBox(L"WSAStartup() failed");
return 1;
//Creating RAW socket for listening
ListenSocket = socket (AF_INET,SOCK_RAW,IPPROTO_IP);
localHost = gethostbyname("");
localIP = inet_ntoa (*(struct in_addr *)*localHost->h_addr_list);
saServer.sin_family = AF_INET;
saServer.sin_addr.s_addr = inet_addr(localIP);
saServer.sin_port = htons(5150);
// Bind the listening socket using the
// information in the sockaddr structure
iResult = bind( ListenSocket,(SOCKADDR*) &saServer, sizeof(saServer) );
if( iResult != 0)
AfxMessageBox(L"Binding the address with the socket failed ");
return 1;
AfxMessageBox(L"Binding successful");
int in_buffer=1, out_buffer;
if (WSAIoctl(ListenSocket,SIO_RCVALL, &in_buffer,sizeof(in_buffer), 0, 0,(LPDWORD) &out_buffer , 0 , 0) == SOCKET_ERROR)
AfxMessageBox(L"WSAIoctl() failed...");
return 1;
AfxMessageBox(L"Socket Set");
CString strText;
int nColumnCount = m_listCtrl.GetHeaderCtrl()->GetItemCount();
StartSniffing(ListenSocket);
closesocket(ListenSocket);
WSACleanup();
return 0;
void CSnifferSampleDlg::StartSniffing(SOCKET sniffer)
char *Buffer = (char *)malloc(65536);
int mangobyte;
if (Buffer == NULL)
printf("malloc() failed.\n");
return;
do
mangobyte = recvfrom(sniffer , Buffer , 65536 , 0 , 0 , 0);
if(mangobyte > 0)
ProcessPacket(Buffer,mangobyte);
/*if(tcp==50)
break;*/
else
printf( "recvfrom() failed.\n");
while (mangobyte > 0);
free(Buffer);
void CSnifferSampleDlg::ProcessPacket(char* buffer,int size)
ip.ValueAssign(buffer);
++total;
//Check the Protocol and do accordingly...
switch (ip.ip_protocol)
case 1: //ICMP Protocol
++icmp;
break;
case 2: //IGMP Protocol
++igmp;
break;
case 6: //TCP Protocol
++tcp;
ProcessTCPPacket(buffer,size);
/*if(tcp==50)
break;*/
break;
case 17: //UDP Protocol
++udp;
break;
default: //Some Other Protocol like ARP etc.
++others;
break;
printf("TCP : %d UDP : %d ICMP : %d IGMP : %d Others : %d Total : %d\r",tcp,udp,icmp,igmp,others,total);
void CSnifferSampleDlg::ProcessTCPPacket(char* buffer,int size)
unsigned short iphdrlen;
SOCKADDR_IN source;
char* source_addr;
char* destination_addr;
source.sin_addr.s_addr = ip.ip_srcaddr;
source_addr=inet_ntoa(source.sin_addr);
SOCKADDR_IN destination;
wchar_t source_address[20];
wchar_t destination_address[20];
mbstowcs_s(0,source_address,source_addr,strlen(source_addr)+1); //method used to convert char* to LPWSTR
destination.sin_addr.s_addr = ip.ip_destaddr;
destination_addr=inet_ntoa(destination.sin_addr);
mbstowcs_s(0,destination_address,destination_addr,strlen(destination_addr)+1);
m_listCtrl.InsertColumn(3,L"");
m_listCtrl.SetColumnWidth(3, 80);
m_listCtrl.SetRedraw(FALSE);
AddData(m_listCtrl,0,0,source_address);
/*AddData(m_listCtrl,0,1,destination_address);
AddData(m_listCtrl,0,2,L"TCP");*/
m_listCtrl.SetRedraw(TRUE);
m_listCtrl.DeleteColumn(3);
void CSnifferSampleDlg::OnBnClickedButton1()
Startbutton();
即使我使用线程,它也不能正常工作。
数据包嗅探实际上是一个持续过程,直到按下停止按钮。但是在这个程序中,当嗅探完成时,无法按下其他按钮,应用程序卡住了。当我将嗅探限制为 20 或 50 时,只有在这么多数据包之后,我们才能做任何其他事情。但是将应用程序限制为 20 或 50 个数据包是一个很大的缺点。
【问题讨论】:
您绝对应该将基于套接字的数据包侦听器和解析器放入线程中。主线程仅用于 GUI 任务。 【参考方案1】:首先,您绝对应该将基于套接字的数据包 侦听器和解析器进入一个线程。主线程专用于 仅限 GUI 任务。
您需要为列表控件启用虚拟模式。 在这种模式下,列表视图控件本身不承载任何数据。 它所知道的只是当前应该显示的行。实际数据要求 要求。这使您的应用程序负责管理 它显示的数据。
了解更多信息:https://msdn.microsoft.com/en-us/library/ye4z8x58.aspx以下是如何使用它的简短示例:
您需要设置列表控件中的项目数。即使我们没有添加任何内容,该列表仍认为它具有此数量的项目:
m_DataArray
定义为CArray<CDataItemInfo> m_DataArray
;
m_DataListCtrl.SetItemCountEx((int)m_DataArray.GetSize(),
LVSICF_NOSCROLL|LVSICF_NOINVALIDATEALL);
...
BEGIN_MESSAGE_MAP(CListCtrlTestDlg, CDialog)
ON_NOTIFY(LVN_GETDISPINFO, IDC_DATA_LIST, OnGetDispInfoList)
END_MESSAGE_MAP()
void CListCtrlTestDlg::OnGetDispInfoList(NMHDR* pNMHDR, LRESULT* pResult)
NMLVDISPINFO *pDispInfo = reinterpret_cast<NMLVDISPINFO*>(pNMHDR);
LV_ITEM& LstItem = pDispInfo->item;
int nItem = LstItem.iItem;
if(nItem > m_DataArray.GetSize()-1)
return;
const CDataItemInfo& ItemData = m_DataArray[nItem];
if (LstItem.mask & LVIF_TEXT)
//Copy the text to the LV_ITEM structure
//Maximum number of characters is in LstItem.cchTextMax
lstrcpyn(LstItem.pszText, ItemData.GetColumnText(LstItem.iSubItem), LstItem.cchTextMax);
【讨论】:
我是新人所以我真的不知道如何实现虚拟列表控件 阅读 MSDN 以了解如何执行此操作。此外,在 codeproject.com 上有很多关于该主题的文章。 使用线程应用程序后,它实际上并没有正确显示详细信息,列表控件正在闪烁。 你不应该直接从线程更新你的CListCtrl
。线程应该将解析后的数据放入某种std::list<CPacketInfo>
容器数据结构中,并通知主线程(可能通过PostMessage
)数据可用于可视化。请注意,必须保护数据容器(使用临界区或类似机制)。
能否请您提供类似的问题解决链接或示例链接来解决此问题以上是关于添加列表控件元素时MFC应用程序卡住[关闭]的主要内容,如果未能解决你的问题,请参考以下文章