MFC应用程序在添加列表控制元素时卡住 [英] MFC Application getting stuck when adding list control elements

查看:230
本文介绍了MFC应用程序在添加列表控制元素时卡住的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

当将元素添加到列表控件时,MFC应用程序无法单击任何其他按钮,甚至在嗅探网络数据包时关闭按钮。

MFC application getting stuck when adding elements into list control unable to click anyother button or even close button when sniffing network packets.

整个代码如下所示:

// 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();
}

即使我使用线程也不能正常工作。

Even when I used threading it is not working fine.

数据包嗅探实际上是一个继续的过程,直到按下停止按钮。但在这里,在这个程序当嗅探完成没有其他按钮是能够按下,应用程序卡住。当我限制嗅闻说20或50然后,那么多的包只有我们可以做任何其他。但是将应用程序限制为20或50个数据包是一个很大的缺点。

Packet sniffing is actually a continues process until a stop button is pressed. But here in this program when sniffing is done no other buttons are able to be pressed, the application getting stuck. When I restrict the sniffing to say 20 or 50 then after that much packet only we can do anything else. But restricting the application to 20 or 50 packets is a big disadvantage.

推荐答案


  1. 首先,你应该把你的基于socket的包
    侦听器和解析器放到一个线程中。主线程专用于
    GUI任务。

  1. First of all you should definitely put your socket-based packet listener and parser into a thread. The main thread is dedicated for GUI tasks only.

您需要为列表控件启用虚拟模式。
在此模式下,列表视图控件不托管任何数据本身。
所有它知道是应该当前显示的行。在
需求上请求实际数据。

You need to enable virtual mode for your list control. In this mode, the list view control doesn't host any data itself. All it knows is rows that should be currently displayed. The actual data is requested on demand. That makes your application responsible for managing the data it displays.

这里是如何使用它的简短示例:

Here is short example on how to use it:

您需要设置列表控件中的项目数。即使我们没有添加任何内容,列表也认为它有这个数目:

You need to set the number of items in the list control. The list thinks it has this number of items even though we have not added anything:

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);
    }

}

这篇关于MFC应用程序在添加列表控制元素时卡住的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆