Lesson15多线程与聊天室程序的创建 VS2013 VC++深入详解 孙鑫

1. 新建项目Chat

2. UI操作

3. 代码

3.1 初始化socket

3.2 ChatDlg.h : header file

3.3 ChatDlg.cpp

4. 程序执行画面


1. 新建项目Chat

MFC Application->Dialog Based(基于对话框的)exe项目

2. UI操作

将自带的文本控件与按钮控件删除。

将发送按钮(IDC_BTN_SEND)设置为默认,用户按Enter即可发送消息

 

将按钮Visible设置为True,按钮就会被隐藏了。

 

 

3. 代码

3.1 初始化socket

//add this header in "stdafx.h"
#include <afxsock.h>	//for AfxSocketInit


// Chat.cpp : Defines the class behaviors for the application.
//

#include "stdafx.h"
#include "Chat.h"
#include "ChatDlg.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#endif


// CChatApp

BEGIN_MESSAGE_MAP(CChatApp, CWinApp)
	ON_COMMAND(ID_HELP, &CWinApp::OnHelp)
END_MESSAGE_MAP()


// CChatApp construction

CChatApp::CChatApp()
{
	// support Restart Manager
	m_dwRestartManagerSupportFlags = AFX_RESTART_MANAGER_SUPPORT_RESTART;

	// TODO: add construction code here,
	// Place all significant initialization in InitInstance
}


// The one and only CChatApp object

CChatApp theApp;


// CChatApp initialization

BOOL CChatApp::InitInstance()
{
	// InitCommonControlsEx() is required on Windows XP if an application
	// manifest specifies use of ComCtl32.dll version 6 or later to enable
	// visual styles.  Otherwise, any window creation will fail.
	INITCOMMONCONTROLSEX InitCtrls;
	InitCtrls.dwSize = sizeof(InitCtrls);
	// Set this to include all the common control classes you want to use
	// in your application.
	InitCtrls.dwICC = ICC_WIN95_CLASSES;
	InitCommonControlsEx(&InitCtrls);

	CWinApp::InitInstance();
    //Load socket library
	if (FALSE == AfxSocketInit())
	{
		AfxMessageBox("Load Socket Fail!!");
		return FALSE;
	}
	

	AfxEnableControlContainer();

	// Create the shell manager, in case the dialog contains
	// any shell tree view or shell list view controls.
	CShellManager *pShellManager = new CShellManager;

	// Activate "Windows Native" visual manager for enabling themes in MFC controls
	CMFCVisualManager::SetDefaultManager(RUNTIME_CLASS(CMFCVisualManagerWindows));

	// Standard initialization
	// If you are not using these features and wish to reduce the size
	// of your final executable, you should remove from the following
	// the specific initialization routines you do not need
	// Change the registry key under which our settings are stored
	// TODO: You should modify this string to be something appropriate
	// such as the name of your company or organization
	SetRegistryKey(_T("Local AppWizard-Generated Applications"));

	CChatDlg dlg;
	m_pMainWnd = &dlg;
	INT_PTR nResponse = dlg.DoModal();
	if (nResponse == IDOK)
	{
		// TODO: Place code here to handle when the dialog is
		//  dismissed with OK
	}
	else if (nResponse == IDCANCEL)
	{
		// TODO: Place code here to handle when the dialog is
		//  dismissed with Cancel
	}
	else if (nResponse == -1)
	{
		TRACE(traceAppMsg, 0, "Warning: dialog creation failed, so application is terminating unexpectedly.\n");
		TRACE(traceAppMsg, 0, "Warning: if you are using MFC controls on the dialog, you cannot #define _AFX_NO_MFC_CONTROLS_IN_DIALOGS.\n");
	}

	// Delete the shell manager created above.
	if (pShellManager != NULL)
	{
		delete pShellManager;
	}

	// Since the dialog has been closed, return FALSE so that we exit the
	//  application, rather than start the application's message pump.
	return FALSE;
}

3.2 ChatDlg.h : header file

// ChatDlg.h : header file
//

#pragma once

struct RECVPARAM{
	SOCKET sock;
	HWND hWnd;
};

#define WM_RECVDATA WM_USER +1

// CChatDlg dialog
class CChatDlg : public CDialogEx
{
// Construction
public:
	CChatDlg(CWnd* pParent = NULL);	// standard constructor

// Dialog Data
	enum { IDD = IDD_CHAT_DIALOG };

	protected:
	virtual void DoDataExchange(CDataExchange* pDX);	// DDX/DDV support


// Implementation
protected:
	HICON m_hIcon;

	// Generated message map functions
	virtual BOOL OnInitDialog();
	afx_msg void OnSysCommand(UINT nID, LPARAM lParam);
	afx_msg void OnPaint();
	afx_msg HCURSOR OnQueryDragIcon();
	afx_msg LRESULT OnRecvData(WPARAM wParam, LPARAM lParam);
	DECLARE_MESSAGE_MAP()
public:
	bool InitSocket();

private:
	SOCKET m_socket;
public:	
	static DWORD  WINAPI RecvProc(LPVOID   lpParameter);
	afx_msg void OnBnClickedBtnSend();
};

3.3 ChatDlg.cpp


// ChatDlg.cpp : implementation file
//

#include "stdafx.h"
#include "Chat.h"
#include "ChatDlg.h"
#include "afxdialogex.h"


#ifdef _DEBUG
#define new DEBUG_NEW
#endif


// CAboutDlg dialog used for App About

class CAboutDlg : public CDialogEx
{
public:
	CAboutDlg();

// Dialog Data
	enum { IDD = IDD_ABOUTBOX };

	protected:
	virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV support

// Implementation
protected:
	DECLARE_MESSAGE_MAP()
};

CAboutDlg::CAboutDlg() : CDialogEx(CAboutDlg::IDD)
{
}

void CAboutDlg::DoDataExchange(CDataExchange* pDX)
{
	CDialogEx::DoDataExchange(pDX);
}

BEGIN_MESSAGE_MAP(CAboutDlg, CDialogEx)
END_MESSAGE_MAP()


// CChatDlg dialog



CChatDlg::CChatDlg(CWnd* pParent /*=NULL*/)
	: CDialogEx(CChatDlg::IDD, pParent)
{
	m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
}

void CChatDlg::DoDataExchange(CDataExchange* pDX)
{
	CDialogEx::DoDataExchange(pDX);
}

BEGIN_MESSAGE_MAP(CChatDlg, CDialogEx)
	ON_WM_SYSCOMMAND()
	ON_WM_PAINT()
	ON_WM_QUERYDRAGICON()
	ON_MESSAGE(WM_RECVDATA, OnRecvData)		//OnRecvData Message
	ON_BN_CLICKED(IDC_BTN_SEND, &CChatDlg::OnBnClickedBtnSend)
END_MESSAGE_MAP()


// CChatDlg message handlers

BOOL CChatDlg::OnInitDialog()
{
	CDialogEx::OnInitDialog();

	// Add "About..." menu item to system menu.

	// IDM_ABOUTBOX must be in the system command range.
	ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
	ASSERT(IDM_ABOUTBOX < 0xF000);

	CMenu* pSysMenu = GetSystemMenu(FALSE);
	if (pSysMenu != NULL)
	{
		BOOL bNameValid;
		CString strAboutMenu;
		bNameValid = strAboutMenu.LoadString(IDS_ABOUTBOX);
		ASSERT(bNameValid);
		if (!strAboutMenu.IsEmpty())
		{
			pSysMenu->AppendMenu(MF_SEPARATOR);
			pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
		}
	}

	// 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
	InitSocket();
	RECVPARAM * pRecvParam = new RECVPARAM;
	pRecvParam->sock = m_socket;
	pRecvParam->hWnd = m_hWnd;

	HANDLE hThread = CreateThread(NULL, 0, RecvProc, (LPVOID)pRecvParam, 0, NULL);

	return TRUE;  // return TRUE  unless you set the focus to a control
}

void CChatDlg::OnSysCommand(UINT nID, LPARAM lParam)
{
	if ((nID & 0xFFF0) == IDM_ABOUTBOX)
	{
		CAboutDlg dlgAbout;
		dlgAbout.DoModal();
	}
	else
	{
		CDialogEx::OnSysCommand(nID, lParam);
	}
}

// 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 CChatDlg::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 CChatDlg::OnQueryDragIcon()
{
	return static_cast<HCURSOR>(m_hIcon);
}



bool CChatDlg::InitSocket()
{
	m_socket = socket(AF_INET, SOCK_DGRAM, 0);		//UDP - User Datagram Protocol
	if (INVALID_SOCKET == m_socket)
	{
		MessageBox("Create socket fail");
		return FALSE;
	}
	SOCKADDR_IN addrSock;
	addrSock.sin_family = AF_INET;
	addrSock.sin_port = htons(6000);
	addrSock.sin_addr.S_un.S_addr = htonl(INADDR_ANY);
	
	int iRetVal;
	iRetVal = bind(m_socket, (SOCKADDR *)&addrSock, sizeof(addrSock));
	if (iRetVal == SOCKET_ERROR)
	{
		MessageBox("bind socket error", "Error");
		return FALSE;
	}

	return false;
}


//Receive Process
//
DWORD  WINAPI CChatDlg::RecvProc(LPVOID   lpParameter)
{
	//get information from main thread
	SOCKET sock = ((RECVPARAM *)lpParameter)->sock;
	HWND hWnd = ((RECVPARAM *)lpParameter)->hWnd;
	delete lpParameter;

	SOCKADDR_IN addrFrom;
	int len = sizeof(SOCKADDR);
	char recvBuf[256];
	char tempBuf[512];
	int recvLen = sizeof(recvBuf);	//recvLen = 256??
	//sprintf_s(tempBuf, "%d", recvLen);
	//::MessageBox(NULL, tempBuf, "recvLen", MB_OK);	//recvLen = 256

	int retVal;
	while (true)
	{
		retVal = recvfrom(sock, recvBuf, 256, 0, (SOCKADDR *)&addrFrom, &len);
		if (SOCKET_ERROR == retVal)
		{
			break;
		}

		char sendAddrBuf[20] = { '\0' };
		inet_ntop(AF_INET, (void*)&addrFrom.sin_addr, sendAddrBuf, 16);		
		//::MessageBox(NULL, sendAddrBuf, "sendAddrBuf",MB_OK);	//sendAddrBuf = "127.0.0.1"
		//sprintf_s(tempBuf, "%s said: %s", inet_ntoa(addrFrom.sin_addr), recvBuf);	//depreciated
		sprintf_s(tempBuf, "%s said: %s", sendAddrBuf, recvBuf);
		::PostMessage(hWnd, WM_RECVDATA, 0, (LPARAM)tempBuf);		
	}
	return 0;
}

//Receive Data
//
LRESULT CChatDlg::OnRecvData(WPARAM wParam, LPARAM lParam)
{
	LRESULT lResult = 0;
	CString str = (char *)lParam;
	CString strTemp;
	GetDlgItemText(IDC_EDIT_RECV, strTemp);
	str += "\r\n";
	str += strTemp;

	//show receive data
	SetDlgItemText(IDC_EDIT_RECV, str);

	return lResult;
}


void CChatDlg::OnBnClickedBtnSend()
{
	// TODO: Add your control notification handler code here
	//get receiver's IP
	DWORD dwIP;
	((CIPAddressCtrl *)GetDlgItem(IDC_IPADDRESS1))->GetAddress(dwIP);

	SOCKADDR_IN addrTo;
	addrTo.sin_family = AF_INET;
	addrTo.sin_port = htons(6000);
	addrTo.sin_addr.S_un.S_addr = htonl(dwIP);

	CString strSend;
	//get data to send
	GetDlgItemText(IDC_EDIT_SEND, strSend);
	//send data
	sendto(m_socket, strSend, strSend.GetLength() + 1,0, 
		(SOCKADDR *)&addrTo, sizeof(SOCKADDR));

	//Clear text edit
	SetDlgItemText(IDC_EDIT_SEND, "");
}

4. 程序执行画面

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值