// NetChatDlg.cpp : implementation file
//
#include "stdafx.h"
#include "NetChat.h"
#include "NetChatDlg.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
/////////////////////////////////////////////////////////////////////////////
// CNetChatDlg dialog
CNetChatDlg::CNetChatDlg(CWnd* pParent /*=NULL*/)
: CDialog(CNetChatDlg::IDD, pParent)
{
//{{AFX_DATA_INIT(CNetChatDlg)
m_bAllUser = FALSE;
m_strChatMsg = _T("");
m_strChatInfo = _T("");
//}}AFX_DATA_INIT
// Note that LoadIcon does not require a subsequent DestroyIcon in Win32
m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
}
void CNetChatDlg::DoDataExchange(CDataExchange* pDX)
{
CDialog::DoDataExchange(pDX);
//{{AFX_DATA_MAP(CNetChatDlg)
DDX_Text(pDX, IDC_CHAT_MSG, m_strChatMsg);
DDX_Text(pDX, IDC_CHAT_INFO, m_strChatInfo);
DDX_Check(pDX, IDC_ALL_USER, m_bAllUser);
DDX_Control(pDX, IDC_USER_LIST, m_ctrlUserList);
DDX_Control(pDX, IDC_RECV_USER, m_ctrlRecvUser);
//}}AFX_DATA_MAP
}
BEGIN_MESSAGE_MAP(CNetChatDlg, CDialog)
//{{AFX_MSG_MAP(CNetChatDlg)
ON_WM_DESTROY()
ON_BN_CLICKED(IDC_SEND_MSG, OnSendMsg)
ON_BN_CLICKED(IDC_SEND_FILE, OnSendFile)
ON_BN_CLICKED(IDC_DLG_EXIT, OnDlgExit)
ON_BN_CLICKED(IDC_USER_FRESH, OnUserFresh)
ON_NOTIFY(NM_CLICK, IDC_USER_LIST, OnClkUserList)
//}}AFX_MSG_MAP
ON_MESSAGE(WM_TCPACCEPT, OnTCPAccept)//为WM_TCPACCEPT消息添加消息宏
ON_MESSAGE(WM_UDPRECEIVE, OnUDPReceive)
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// CNetChatDlg message handlers
BOOL CNetChatDlg::OnInitDialog()
{
CDialog::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
// initialize user list
m_ctrlUserList.SetExtendedStyle(LVS_EX_FULLROWSELECT|LVS_EX_GRIDLINES|LVS_REPORT);
m_ctrlUserList.InsertColumn(0, "状态", LVCFMT_LEFT, 60);
m_ctrlUserList.InsertColumn(1, "用户名", LVCFMT_LEFT, 100);
m_ctrlUserList.InsertColumn(2, "主机名", LVCFMT_LEFT, 120);
m_ctrlUserList.InsertColumn(3, "IP地址", LVCFMT_LEFT, 120);
//取得本地用户信息,并保存到成员变量m_tLcoalUsr中
memset(&m_tLocalUsr, 0, sizeof(USERINFO));//将m_tLocalUsr成员变量清零,并设置本地用户为在线状态
unsigned long nSize = 0;
m_tLocalUsr.nState = USER_ONLINE; //用户在线状态
nSize = sizeof(m_tLocalUsr.szName);
::GetUserName(m_tLocalUsr.szName, &nSize); //取得系统用户名
nSize = sizeof(m_tLocalUsr.szHost);
::GetComputerName(m_tLocalUsr.szHost, &nSize); //取得系统zhuji名
hostent* phost = ::gethostbyname(m_tLocalUsr.szHost); //获得主机IP地址等网络信息
strcpy(m_tLocalUsr.szAddr, inet_ntoa(*(struct in_addr*)phost->h_addr_list[0]));//将IP地址转换为主机字节顺序的ASCII码字符串形式,并保存至m_tLocalUsr中
m_pUDPClient = new CUDPSocket(this); //创建UDP客户端
m_pUDPClient->CreateClient(m_tLocalUsr.szAddr, UDP_PORTNR);
m_pTCPServer = new CTCPSocket(this); //创建TCP服务器
m_pTCPServer->CreateServer(m_tLocalUsr.szAddr, TCP_PORTNR);
OnUserFresh();
return TRUE; // return TRUE unless you set the focus to a control
}
void CNetChatDlg::SetChatMsg(CString strMsg)
{
// 添加发送的消息
m_strChatInfo += strMsg+"\r\n";
SetDlgItemText(IDC_CHAT_INFO, m_strChatInfo);
// 实现滚动
CEdit *pEdit = (CEdit*)GetDlgItem(IDC_CHAT_INFO);
pEdit->LineScroll(pEdit->GetLineCount());
}
USERINFO* CNetChatDlg::FindUser(CString strAddr)//根据IP地址,从用户信息链表中查找对应的用户,返回对应指针
{
if (strAddr.IsEmpty()) //IP地址为空直接返回
return NULL;
USERINFO *pInfo = NULL;
POSITION pos = m_lsUsrInfo.GetHeadPosition();
while (pos != NULL)
{
pInfo = (USERINFO*)m_lsUsrInfo.GetAt(pos);
m_lsUsrInfo.GetNext(pos);
if (strAddr.Compare(pInfo->szAddr) == 0)//比较IP地址与取得用户IP地址
return pInfo; //返回查找用户信息
}
return NULL;
}
void CNetChatDlg::UpdateUserList()//将用户链表中的信息添加到列表控件:m_ctrlUSERList中
{
m_ctrlRecvUser.ResetContent();//清空接收人组合框中的内容
m_ctrlUserList.DeleteAllItems();//清空用户列表中的内容
int nItem = 0;
USERINFO *pInfo = NULL;
POSITION pos = m_lsUsrInfo.GetHeadPosition();//获得链表头项
while (pos != NULL)
{
pInfo = (USERINFO*)m_lsUsrInfo.GetAt(pos);//取得用户信息
m_lsUsrInfo.GetNext(pos); //取得下一个用户信息
m_ctrlUserList.InsertItem(nItem, "");
m_ctrlUserList.SetItemText(nItem, 0, "在线");
m_ctrlUserList.SetItemText(nItem, 1, pInfo->szName);
m_ctrlUserList.SetItemText(nItem, 2, pInfo->szHost);
m_ctrlUserList.SetItemText(nItem, 3, pInfo->szAddr);
nItem++;
m_ctrlRecvUser.AddString(pInfo->szName);//将用户名添加到接收人组合框中
}
CString strNum;
strNum.Format("%d", nItem);
SetDlgItemText(IDC_USER_NUM, strNum);//设置在线人数
m_ctrlRecvUser.SetCurSel(0);//默认选中的接收人
}
void CNetChatDlg::OnUserFresh()
{
ASSERT_VALID(m_pUDPClient);
SENDDATA sd;
sd.nType = TYPE_USERINFO;
strcpy(sd.szSend, m_tLocalUsr.szAddr);//将本地用户信息复制到SENDATA中的发送方信息中
memcpy(sd.szData, &m_tLocalUsr, sizeof(USERINFO));//将本地信息存入SENDATA数据缓冲区
m_pUDPClient->SendTo(&sd, sizeof(SENDDATA), UDP_PORTNR);//向网络广播本地信息
}
void CNetChatDlg::DisplaySentMessage(SENDDATA *sd)
{
CString chatHeader = m_tLocalUsr.szName;
CString chatTime;
CTime timeChatting = CTime::GetCurrentTime();
int year = timeChatting.GetYear(); //年
int month = timeChatting.GetMonth(); //月
int day = timeChatting.GetDay(); //日
int hour = timeChatting.GetHour(); //时
int minute = timeChatting.GetMinute(); //分
int second = timeChatting.GetSecond(); //秒
chatTime.Format(" (%d-%d-%d %d:%d:%d)", year, month, day, hour, minute, second);
chatHeader += chatTime;//消息头
m_strChatInfo += chatHeader, m_strChatInfo += ":\r\n";
m_strChatInfo += sd->szData, m_strChatInfo += "\r\n";
SetDlgItemText(IDC_CHAT_INFO, m_strChatInfo);
// 内容可上下滚动
CEdit *pEdit = (CEdit*)GetDlgItem(IDC_CHAT_INFO);
pEdit->LineScroll(pEdit->GetLineCount());
return ;
}
void CNetChatDlg::OnSendMsg()
{
UpdateData(TRUE);
SENDDATA sd;
memset(&sd, 0, sizeof(SENDDATA));//将m_tLocalUsr成员变量清零,并设置用户为在线状态;
sd.nType = TYPE_CHATDATA; //将数据类型设置为聊天类型
strcpy(sd.szSend, m_tLocalUsr.szAddr);//将将本地用户信息复制到SENDDATA数据缓冲区中,本地用户为消息发送方
if (m_strChatMsg.IsEmpty())
return; //判断发送消息是否为空
GetDlgItemText(IDC_CHAT_MSG, sd.szData, sizeof(sd.szData));//将IDC_CHAT_MSG控件发送的消息复制到sd.szData
DisplaySentMessage(&sd);//给对方发送的信息对自己可见
SendToUser(&sd);//向用户发送消息
//清空编辑框内容
GetDlgItem(IDC_CHAT_MSG)->SetWindowText("");
UpdateData();
}
void CNetChatDlg::OnSendFile()
{
UpdateData(TRUE);
SENDDATA sd;
memset(&sd, 0, sizeof(SENDDATA));
//选择文件
char szFilter[] = "所有文件 (*.*)|*.*||";//文件过滤字符串
CFileDialog dlg(TRUE, NULL, NULL,
OFN_HIDEREADONLY|OFN_OVERWRITEPROMPT, szFilter);
if (dlg.DoModal() != IDOK) //弹出对话框,选择文件
return;
FILEINFO fi;
memset(&fi, 0, sizeof(FILEINFO));
CString strName = dlg.GetFileName(); //取得文件名
strcpy(fi.szFile, strName.GetBuffer(0));
strName.ReleaseBuffer();
strName = dlg.GetPathName(); //取得文件名路径
strcpy(fi.szPath, strName.GetBuffer(0));