📄 clientdlg.cpp
字号:
// ClientDlg.cpp : 实现文件
//
#include "stdafx.h"
#include "Client.h"
#include "ClientDlg.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#endif
// 用于应用程序“关于”菜单项的 CAboutDlg 对话框
class CAboutDlg : public CDialog
{
public:
CAboutDlg();
// 对话框数据
enum { IDD = IDD_ABOUTBOX };
protected:
virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV 支持
// 实现
protected:
DECLARE_MESSAGE_MAP()
};
CAboutDlg::CAboutDlg() : CDialog(CAboutDlg::IDD)
{
}
void CAboutDlg::DoDataExchange(CDataExchange* pDX)
{
CDialog::DoDataExchange(pDX);
}
BEGIN_MESSAGE_MAP(CAboutDlg, CDialog)
END_MESSAGE_MAP()
// CClientDlg 对话框
CClientDlg::CClientDlg(CWnd* pParent /*=NULL*/)
: CDialog(CClientDlg::IDD, pParent)
, m_dwBytesRECV(0)
,m_RecvBuff(512)
,m_SendBuff(512)
, m_isConnect(false)
, m_szName(_T(""))
, m_Timer(0)
, m_ePort(27015)
{
ConnectSocket = INVALID_SOCKET;
m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
}
void CClientDlg::DoDataExchange(CDataExchange* pDX)
{
CDialog::DoDataExchange(pDX);
DDX_Text(pDX, IDE_PORT, m_ePort);
}
BEGIN_MESSAGE_MAP(CClientDlg, CDialog)
ON_WM_SYSCOMMAND()
ON_WM_PAINT()
ON_WM_QUERYDRAGICON()
//}}AFX_MSG_MAP
ON_MESSAGE(WM_SOCKET,&CClientDlg::OnSocketEvent)
ON_BN_CLICKED(IDB_CONNECT, &CClientDlg::OnBnConnect)
ON_BN_CLICKED(IDB_SEND, &CClientDlg::OnBnSend)
ON_WM_TIMER()
END_MESSAGE_MAP()
// CClientDlg 消息处理程序
BOOL CClientDlg::OnInitDialog()
{
CDialog::OnInitDialog();
// 将“关于...”菜单项添加到系统菜单中。
// IDM_ABOUTBOX 必须在系统命令范围内。
ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
ASSERT(IDM_ABOUTBOX < 0xF000);
CMenu* pSysMenu = GetSystemMenu(FALSE);
if (pSysMenu != NULL)
{
CString strAboutMenu;
strAboutMenu.LoadString(IDS_ABOUTBOX);
if (!strAboutMenu.IsEmpty())
{
pSysMenu->AppendMenu(MF_SEPARATOR);
pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
}
}
// 设置此对话框的图标。当应用程序主窗口不是对话框时,框架将自动
// 执行此操作
SetIcon(m_hIcon, TRUE); // 设置大图标
SetIcon(m_hIcon, FALSE); // 设置小图标
//SetDlgItemInt(IDE_PORT,27015);
SetDlgItemText(IDI_ADDRESS,L"127.0.0.1");
((CListCtrl*)GetDlgItem(IDL_USER))->InsertColumn(0,L"Members",LVCFMT_LEFT,80,-1);
((CListCtrl*)GetDlgItem(IDL_USER))->InsertColumn(1,L"Messages",LVCFMT_LEFT,100,-1);
return TRUE; // 除非将焦点设置到控件,否则返回 TRUE
}
void CClientDlg::OnSysCommand(UINT nID, LPARAM lParam)
{
if ((nID & 0xFFF0) == IDM_ABOUTBOX)
{
CAboutDlg dlgAbout;
dlgAbout.DoModal();
}
else
{
CDialog::OnSysCommand(nID, lParam);
}
}
// 如果向对话框添加最小化按钮,则需要下面的代码
// 来绘制该图标。对于使用文档/视图模型的 MFC 应用程序,
// 这将由框架自动完成。
void CClientDlg::OnPaint()
{
if (IsIconic())
{
CPaintDC dc(this); // 用于绘制的设备上下文
SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0);
// 使图标在工作区矩形中居中
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;
// 绘制图标
dc.DrawIcon(x, y, m_hIcon);
}
else
{
CDialog::OnPaint();
}
}
HCURSOR CClientDlg::OnQueryDragIcon()
{
return static_cast<HCURSOR>(m_hIcon);
}
void CClientDlg::OnBnConnect()
{
int iResult;
CString strErr;
WSADATA wsaData;
ADDRINFOW *result = NULL,*ptr = NULL;
ADDRINFOW hints;
CString ServerPort;
CString ServerIP;
GetDlgItemText(IDE_NAME,m_szName);
if (m_szName.GetLength() <= 0)return ;
if (m_isConnect)
{
closesocket(ConnectSocket);
WSACleanup();
m_isConnect = false;
//KillTimer(m_Timer);
GetDlgItem(IDE_NAME)->EnableWindow(TRUE);
GetDlgItem(IDE_PORT)->EnableWindow(TRUE);
GetDlgItem(IDI_ADDRESS)->EnableWindow(TRUE);
SetDlgItemText(IDB_CONNECT,L"Connect");
while ( ((CListCtrl*)GetDlgItem(IDL_USER))->DeleteItem (1));
return ;
}
GetDlgItemText(IDE_PORT,ServerPort);
GetDlgItemText(IDI_ADDRESS,ServerIP);
((CListCtrl*)GetDlgItem(IDL_USER))->InsertColumn(0,L"Members",LVCFMT_LEFT,80,-1);
((CListCtrl*)GetDlgItem(IDL_USER))->InsertColumn(1,L"Messages",LVCFMT_LEFT,100,-1);
iResult = WSAStartup(MAKEWORD(2,2), &wsaData);
if (iResult != 0) {
strErr.Format(L"WSAStartup failed: %d\n", iResult);
MessageBox(strErr);
return ;
}
ZeroMemory( &hints, sizeof(hints) );
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = IPPROTO_TCP;
iResult = GetAddrInfo(ServerIP,ServerPort, &hints, &result);
if ( iResult != 0 ) {
strErr.Format(L"getaddrinfo failed: %d\n", iResult);
MessageBox(strErr);
WSACleanup();
return ;
}
for(ptr=result; ptr != NULL ;ptr=ptr->ai_next) {
// Create a SOCKET for connecting to server
ConnectSocket = socket(ptr->ai_family, ptr->ai_socktype,
ptr->ai_protocol);
if (ConnectSocket == INVALID_SOCKET) {
strErr.Format(L"Error at socket(): %ld\n", WSAGetLastError());
MessageBox(strErr);
FreeAddrInfo(result);
WSACleanup();
return ;
}
// Connect to server.
iResult = connect( ConnectSocket, ptr->ai_addr, (int)ptr->ai_addrlen);
if (iResult == SOCKET_ERROR) {
closesocket(ConnectSocket);
ConnectSocket = INVALID_SOCKET;
continue;
}
break;
}
FreeAddrInfo(result);
if (ConnectSocket == INVALID_SOCKET) {
MessageBox(L"Unable to connect to server!\n");
WSACleanup();
return ;
}
if((WSAAsyncSelect(ConnectSocket, this->m_hWnd, WM_SOCKET, FD_READ|FD_WRITE|FD_CLOSE))==SOCKET_ERROR){
MessageBox(L"WSAAsyncSelect error");
return ;
}
CMsg loginMsg;
ZeroMemory(&loginMsg,sizeof loginMsg);
loginMsg.MsgHead.eCmdID = CMD_LOGIN;
loginMsg.MsgHead.dwToken = 0;
loginMsg.MsgHead.dwLength = sizeof CMD_ID+2*sizeof DWORD+NAME_LEN*4;
memcpy(loginMsg.MsgLogin.szUsername,m_szName,(m_szName.GetLength()+1)*2);
SendMsg(&loginMsg);
m_isConnect = true;
GetDlgItem(IDE_NAME)->EnableWindow(FALSE);
GetDlgItem(IDE_PORT)->EnableWindow(FALSE);
GetDlgItem(IDI_ADDRESS)->EnableWindow(FALSE);
SetDlgItemText(IDB_CONNECT,L"Disconnect");
//m_Timer = SetTimer(1,1000,NULL);
}
#define DATA_BUFSIZE 512
LRESULT CClientDlg::OnSocketEvent(WPARAM wParam,LPARAM lParam){
CString strErr;
CString strMsg;
LVFINDINFO FindInfo;
if (WSAGETSELECTERROR(lParam))
{
PostMessage(WM_SOCKET,wParam,FD_CLOSE);
//FreeSocketInformation(wParam);
}
else
{
switch(WSAGETSELECTEVENT(lParam)){
case FD_READ:
if(RecvMsg()){
CMsg * ptrMsg = new CMsg;
if(!DecodingBuff(ptrMsg)){
delete ptrMsg;
m_RecvBuff.ReSet();
break;
}
if(ptrMsg->MsgHead.eCmdID == CMD_MSG_CHAT){
FindInfo.flags = LVFI_STRING;
FindInfo.psz = ptrMsg->MsgNew.szUsername;
int iIndex = ((CListCtrl*)GetDlgItem(IDL_USER))->FindItem(&FindInfo);
int iMsgs=_wtoi(((CListCtrl*)GetDlgItem(IDL_USER))->GetItemText(iIndex,1));
strMsg.Format(L"%d",++iMsgs);
((CListCtrl*)GetDlgItem(IDL_USER))->SetItemText(iIndex,1,strMsg);
strMsg.Format(L"%s Say:\n%s\n",ptrMsg->MsgChat.szSender,ptrMsg->MsgChat.szContent);
}
else if (ptrMsg->MsgHead.eCmdID == CMD_NEW)
{
strMsg.Format(L"%s Login\n",ptrMsg->MsgNew.szUsername);
((CListCtrl*)GetDlgItem(IDL_USER))->InsertItem(0,ptrMsg->MsgNew.szUsername);
((CListCtrl*)GetDlgItem(IDL_USER))->SetItemText(0,1,L"0");
}
else if(ptrMsg->MsgHead.eCmdID == CMD_LOGOUT){
strMsg.Format(L"%s Logout\n",ptrMsg->MsgNew.szUsername);
FindInfo.flags = LVFI_STRING;
FindInfo.psz = ptrMsg->MsgNew.szUsername;
((CListCtrl*)GetDlgItem(IDL_USER))->DeleteItem(
((CListCtrl*)GetDlgItem(IDL_USER))->FindItem(&FindInfo));
}
m_RecvBuff.ReSet();
delete ptrMsg;
((CEdit*)GetDlgItem(IDE_RECV_MSG))->SetSel(-1);
((CEdit*)GetDlgItem(IDE_RECV_MSG))->ReplaceSel(strMsg);
}
break;
// DO NOT BREAK HERE SINCE WE GOT A SUCCESSFUL RECV. Go ahead
// and begin writing data to the client.
case FD_WRITE:
//GetDlgItemText(IDE_SEND_MSG,strMsg);
break;
case FD_CLOSE:
GetDlgItem(IDE_NAME)->EnableWindow(TRUE);
GetDlgItem(IDE_PORT)->EnableWindow(TRUE);
GetDlgItem(IDI_ADDRESS)->EnableWindow(TRUE);
while ( ((CListCtrl*)GetDlgItem(IDL_USER))->DeleteItem (1));
SetDlgItemText(IDB_CONNECT,L"Connect");
m_isConnect = FALSE;
closesocket(ConnectSocket);
WSACleanup();
break;
}
}
return 0;
}
void CClientDlg::OnBnSend()
{
CString strMsg;
DWORD strLen = 0;
CMD_ID MsgType = CMD_MSG_CHAT;
DWORD dwLen = 0;
GetDlgItemText(IDE_SEND_MSG,strMsg);
strLen = strMsg.GetLength();
if (strLen <= 0)
{
//do not send empty msg
return ;
}
CMsg newMsg;
newMsg.MsgHead.eCmdID = CMD_MSG_CHAT;
newMsg.MsgHead.dwToken = 0;
newMsg.MsgHead.dwLength = sizeof CMD_ID+3*sizeof DWORD+NAME_LEN*2+(strLen+1)*2;
memcpy(newMsg.MsgChat.szSender,m_szName,(m_szName.GetLength()+1)*2);
newMsg.MsgChat.dwLength = (strLen+1)*2;
newMsg.MsgChat.szContent = new wchar_t[strLen+1];
memcpy(newMsg.MsgChat.szContent,strMsg,newMsg.MsgChat.dwLength);
SendMsg(&newMsg);
strMsg = m_szName + L"Say:"+strMsg;
strMsg+=L"\n";
((CEdit*)GetDlgItem(IDE_RECV_MSG))->SetSel(-1);
((CEdit*)GetDlgItem(IDE_RECV_MSG))->ReplaceSel(strMsg);
SetDlgItemText(IDE_SEND_MSG,L"");
}
bool CClientDlg::DecodingBuff(CMsg* ptrMsg)
{
if (!ptrMsg)return FALSE;
DWORD dwPos = 0;
m_RecvBuff.GetFromBuffer((char*)(&(ptrMsg->MsgHead.dwLength)),dwPos,sizeof DWORD);
dwPos += sizeof DWORD;
m_RecvBuff.GetFromBuffer((char*)(&(ptrMsg->MsgHead.eCmdID)),dwPos,sizeof CMD_ID);
dwPos += sizeof CMD_ID;
m_RecvBuff.GetFromBuffer((char*)(&(ptrMsg->MsgHead.dwToken)),dwPos,sizeof DWORD);
dwPos += sizeof DWORD;
if(ptrMsg->MsgHead.eCmdID == CMD_MSG_CHAT){
m_RecvBuff.GetFromBuffer((char*)ptrMsg->MsgChat.szSender,dwPos,sizeof ptrMsg->MsgChat.szSender);
dwPos += sizeof ptrMsg->MsgChat.szSender;
m_RecvBuff.GetFromBuffer((char*)(&(ptrMsg->MsgChat.dwLength)),dwPos,sizeof DWORD);
dwPos += sizeof DWORD;
ptrMsg->MsgChat.szContent = new wchar_t [ptrMsg->MsgChat.dwLength/2];
m_RecvBuff.GetFromBuffer((char*)ptrMsg->MsgChat.szContent,dwPos,ptrMsg->MsgChat.dwLength);
}
else if(ptrMsg->MsgHead.eCmdID == CMD_NEW){
m_RecvBuff.GetFromBuffer((char*)ptrMsg->MsgNew.szUsername,dwPos,sizeof ptrMsg->MsgNew.szUsername);
}
else if(ptrMsg->MsgHead.eCmdID == CMD_LOGOUT){
m_RecvBuff.GetFromBuffer((char*)ptrMsg->MsgNew.szUsername,dwPos,sizeof ptrMsg->MsgNew.szUsername);
}
return TRUE;
}
void CClientDlg::CodingBuff(CMsg* ptrMsg){
m_SendBuff.AddToBuffer((char*)(&(ptrMsg->MsgHead.dwLength)),sizeof DWORD);
m_SendBuff.AddToBuffer((char*)(&(ptrMsg->MsgHead.eCmdID)),sizeof CMD_ID);
m_SendBuff.AddToBuffer((char*)(&(ptrMsg->MsgHead.dwToken)),sizeof DWORD);
if(ptrMsg->MsgHead.eCmdID == CMD_MSG_CHAT){
m_SendBuff.AddToBuffer((char*)ptrMsg->MsgChat.szSender,sizeof ptrMsg->MsgChat.szSender);
m_SendBuff.AddToBuffer((char*)(&(ptrMsg->MsgChat.dwLength)),sizeof DWORD);
m_SendBuff.AddToBuffer((char*)ptrMsg->MsgChat.szContent,ptrMsg->MsgChat.dwLength);
}
else if(ptrMsg->MsgHead.eCmdID == CMD_LOGIN){
m_SendBuff.AddToBuffer((char*)ptrMsg->MsgLogin.szUsername,sizeof ptrMsg->MsgLogin.szUsername);
m_SendBuff.AddToBuffer((char*)ptrMsg->MsgLogin.szPassWord,sizeof ptrMsg->MsgLogin.szPassWord);
}
}
void CClientDlg::SendMsg(CMsg* ptrMsg)
{
WSABUF wsaBuf;
DWORD SendBytes = 0;
CodingBuff(ptrMsg);
//CMsg msg;
//DecodingBuff(&msg);
wsaBuf.buf = m_SendBuff.GetBuffer();
wsaBuf.len = m_SendBuff.GetLength();
while(SendBytes < wsaBuf.len){
if (WSASend(ConnectSocket, &wsaBuf, 1, &SendBytes, 0,
NULL, NULL) == SOCKET_ERROR)
{
if (WSAGetLastError() != WSAEWOULDBLOCK)
{
printf("WSASend() failed with error %d\n", WSAGetLastError());
//FreeSocketInformation(wParam);
return ;
}
}
}
m_SendBuff.ReSet();
}
bool CClientDlg::RecvMsg()
{
DWORD Flags=0;
char szBuff[DATA_BUFSIZE];
WSABUF wsaBuf;
DWORD RecvBytes;
DWORD BytesRECV=0;
while(BytesRECV != sizeof DWORD){
wsaBuf.buf = szBuff;
wsaBuf.len = sizeof DWORD-BytesRECV;
if (WSARecv(ConnectSocket, &wsaBuf, 1, &RecvBytes,
&Flags, NULL, NULL) == SOCKET_ERROR)
{
if (WSAGetLastError() != WSAEWOULDBLOCK)return FALSE;
}
BytesRECV += RecvBytes;
m_RecvBuff.AddToBuffer(szBuff,RecvBytes);
}
DWORD dwLength;
m_RecvBuff.GetFromBuffer((char*)(&dwLength),0,sizeof DWORD);
while(BytesRECV != dwLength){
wsaBuf.buf = szBuff;
wsaBuf.len = (dwLength-BytesRECV)/DATA_BUFSIZE ? DATA_BUFSIZE:dwLength-BytesRECV;
if (WSARecv(ConnectSocket, &wsaBuf, 1, &RecvBytes,
&Flags, NULL, NULL) == SOCKET_ERROR)
{
if (WSAGetLastError() != WSAEWOULDBLOCK)return FALSE;
}
BytesRECV += RecvBytes;
m_RecvBuff.AddToBuffer(szBuff,RecvBytes);
}
BytesRECV = 0;
return TRUE;
}
void CClientDlg::OnTimer(UINT_PTR nIDEvent)
{
// TODO: Add your message handler code here and/or call default
CString strErr;
CString strMsg;
if(RecvMsg()){
CMsg * ptrMsg = new CMsg;
if(!DecodingBuff(ptrMsg)){
delete ptrMsg;
m_RecvBuff.ReSet();
return ;
}
if(ptrMsg->MsgHead.eCmdID == CMD_MSG_CHAT){
strMsg.Format(L"%s Say:\n%s\n",ptrMsg->MsgChat.szSender,ptrMsg->MsgChat.szContent);
}
else if (ptrMsg->MsgHead.eCmdID == CMD_NEW)
{
strMsg.Format(L"%s Login\n",ptrMsg->MsgNew.szUsername);
}
m_RecvBuff.ReSet();
((CEdit*)GetDlgItem(IDE_RECV_MSG))->SetSel(-1);
((CEdit*)GetDlgItem(IDE_RECV_MSG))->ReplaceSel(strMsg);
}
CDialog::OnTimer(nIDEvent);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -