📄 chatdlg.cpp
字号:
// ChatDlg.cpp : implementation file
//
#include "stdafx.h"
#include "NetMsg.h"
#include "ChatDlg.h"
#include "NetMsgDlg.h"
#include "WorkSocket.h"
#include "ChatDGram.h"
#include "FileTranDlg.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
/////////////////////////////////////////////////////////////////////////////
// CChatDlg dialog
//##ModelId=3E3271770155
CChatDlg::CChatDlg(CWnd* pParent /*=NULL*/)
: CDialog(CChatDlg::IDD, pParent), m_strSelfNickName(""), m_dwSelfNetMsgID(0), m_strPeerIPAddress(""), m_strPeerNickName(""), m_dwPeerNetMsgID(0), m_posPeer(NULL)
{
//{{AFX_DATA_INIT(CChatDlg)
m_strMsg = _T("");
//}}AFX_DATA_INIT
//读入聊天使用的port
/*bool bRet = false;
try
{
IXMLDOMDocumentPtr xmlDoc(__uuidof(DOMDocument));
xmlDoc->async = false; //同步加载XML文件
xmlDoc->load(".\\conf\\config.xml");
bRet = true;
}
catch(_com_error &err)
{
CString strErr = "加载config.xml失败";
strErr += (const char *)err.Description();
AfxMessageBox(strErr);
}*/
}
//##ModelId=3E327177015F
void CChatDlg::DoDataExchange(CDataExchange* pDX)
{
CDialog::DoDataExchange(pDX);
//{{AFX_DATA_MAP(CChatDlg)
DDX_Control(pDX, IDC_EDIT_CHATHIST, m_edtChatHist);
DDX_Control(pDX, IDC_EDIT_MSG, m_edtMsg);
DDX_Control(pDX, IDC_SEND, m_cmdSend);
DDX_Text(pDX, IDC_EDIT_MSG, m_strMsg);
DDV_MaxChars(pDX, m_strMsg, 500);
//}}AFX_DATA_MAP
}
BEGIN_MESSAGE_MAP(CChatDlg, CDialog)
//{{AFX_MSG_MAP(CChatDlg)
ON_BN_CLICKED(IDC_SEND, OnSend)
ON_WM_CLOSE()
ON_WM_DROPFILES()
ON_BN_CLICKED(IDC_FILETRAN, OnFiletran)
//}}AFX_MSG_MAP
ON_MESSAGE(WM_FRIEND_MSG,OnFriendMsg)
ON_MESSAGE(WM_CHAT_MSG, OnChatMsg) // 通知聊天内容已经发送完毕,其中的wPararm == 1
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// CChatDlg message handlers
//##ModelId=3E3273420318
void CChatDlg::SendMsg()
{
TRACE("SendMsg() 开始...\n");
//
// 使用一个UDP的socket
//
CWorkSocket wrkSocket;
BOOL bRet = wrkSocket.Create(0, SOCK_DGRAM);
char buf[1024] = {0};
//
// Set chat Msg header
//
#pragma message(" - Author - Entity problem solved!")
sprintf(buf, "<ChatDiagram>"
"<NetMsgID>%u</NetMsgID>"
"<Msg>%s</Msg>"
"</ChatDiagram>"
, m_dwSelfNetMsgID
, "");
try
{
MSXML::IXMLDOMDocumentPtr xmlDoc(__uuidof(MSXML::DOMDocument));
xmlDoc->MSXML::IXMLDOMDocument::async = false;
xmlDoc->MSXML::IXMLDOMDocument::loadXML(_bstr_t(buf));
xmlDoc->MSXML::IXMLDOMDocument::selectSingleNode("ChatDiagram/Msg")->text = (const char *)m_strMsg;
//
// 使用 ->xml 是为了完成 entity的转换功能,否则不要自己去 encoding xml的entity
//
strncpy(buf, xmlDoc->xml, sizeof(buf));
}
catch(_com_error &e)
{
CString strErr = "发送错误! - com_error: ";
strErr += (const char *)e.Description();
AfxMessageBox(strErr);
}
//
// 把聊天信息XML发送远端m_strPeerIPAddress的shortChatPort上去
//
//发送的时候要把 '\0' 也加上,为了接受的时候方便识别!!!
int nErr = wrkSocket.SendTo(buf, strlen(buf) + 1
, CChatDlg::shortChatPort, m_strPeerIPAddress);
bool bSendOK = (SOCKET_ERROR != nErr);
if (bSendOK)
{
nErr = GetLastError();
TRACE("SendTo error(0x%x)\n", nErr);
}
else
{
//Send OK!!
TRACE("Send chat message ok!!\n");
}
PostMessage(WM_CHAT_MSG, 1, 0);
wrkSocket.Close();
}
//##ModelId=3E3273A10260
void CChatDlg::SaveMsg()
{
TRACE("My NickName is: %s\n", m_strSelfNickName);
SaveMsg(m_strSelfNickName, m_strMsg);
}
//##ModelId=3E3273DF0382
#pragma message("--OnRecv 在收到他人的聊天信息时,如果窗口没有打开,那么信息就不能被显示,这个要修改。")
void CChatDlg::OnRecv(CString strMsg)
{
//m_cs.Lock();
SaveMsg(m_strPeerNickName, strMsg);
//显示到聊天窗口,并滚动窗口到末尾一行
int nLen = m_edtChatHist.GetWindowTextLength();
m_edtChatHist.SetSel(nLen, nLen);
CString strTemp = m_strPeerNickName + ": " + strMsg + "\r\n";
m_edtChatHist.ReplaceSel(strTemp);
//m_cs.Unlock();
}
//##ModelId=3E327F2503D2
UINT CChatDlg::RecvService(LPVOID param)
{
//设置计数器,如果计数器不是0, 那么就表明此服务被启动过一次。
//这个服务只能被启动一次。
static long nCounter = 0;
if (nCounter)
return 1;
InterlockedIncrement(&nCounter);
//传入CNetMsgDlg的一个有效的实例指针
CNetMsgDlg *pNetMsg = (CNetMsgDlg *)param;
if (!pNetMsg)
{
AfxMessageBox(" - RecvService - 应当传入一个有效的 CNetMsgDlg 对象指针!");
ASSERT(FALSE);
}
else
{
pNetMsg = static_cast<CNetMsgDlg *>(pNetMsg);
}
::CoInitialize(NULL);
TRACE("RecvService 开始...\n");
CWorkSocket svrSocket;
//
// 1. 使用shortChatPort来进行接受UDP报文
//
BOOL bErr = svrSocket.Create(CChatDlg::shortChatPort, SOCK_DGRAM);
if (!bErr)
{
TRACE("wrkSocket.Create error(0x%x)\n", GetLastError());
ASSERT(FALSE);
}
//
// 2. 当收到一个 WM_QUIT 的消息的时候就会退出循环。
//
MSG msg;
char buf[1024];
while(!PeekMessage(&msg, NULL, WM_QUIT, WM_QUIT, PM_REMOVE))
{
#pragma message(" - RecvService - 接受到报文的时候应当验证一下发送端使用的端口是否是 shortChatPort")
//3. 等候接受报文
CString r_strSourceIP = "";
UINT r_uSourcePort = 0;
#if !defined(_SIMULATE)
int nErr = svrSocket.ReceiveFrom(buf, sizeof(buf), r_strSourceIP, r_uSourcePort);
TRACE("svrSocket.ReceiveFrom return!\n");
#else
r_strSourceIP = "127.0.0.1";
strcpy(buf, "<ChatDiagram><Msg>Hello Victor</Msg><NetMsgID>1002</NetMsgID></ChatDiagram>");
int nErr = strlen(buf) + 1;
Sleep(2000);
#endif
if (SOCKET_ERROR == nErr)
{
TRACE("RecvService error(0x%x)\n", GetLastError());
}
else if ( 0 == nErr)
{
//远端已经关闭
TRACE(" - RecvService - 远端已经关闭...\n");
}
#pragma message(" - RecvService - 下面是端口验证,如果可以用就要打开。")
else // if ( CChatDlg::shortChatPort == r_uSourcePort)
{
TRACE(" - RecvService - 收到聊天报文...\n");
TRACE("buf=%s\n", buf);
//
//4. 解析XML报文
//
DWORD dwNetMsgID = 0;
CString strMsg = "";
try
{
MSXML::IXMLDOMDocumentPtr xmlDoc(__uuidof(MSXML::DOMDocument));
xmlDoc->MSXML::IXMLDOMDocument::async = false;
xmlDoc->MSXML::IXMLDOMDocument::loadXML(_bstr_t(buf));
dwNetMsgID = atoi((const char *)xmlDoc->MSXML::IXMLDOMDocument::selectSingleNode("ChatDiagram/NetMsgID")->text);
strMsg = (const char *)xmlDoc->MSXML::IXMLDOMDocument::selectSingleNode("ChatDiagram/Msg")->text;
}
catch(_com_error &err)
{
TRACE(CString("XML error in RecvService...\n") + (const char *)err.Description());
}
//5. 组装聊天报文
CChatDGram *pChatDGram = new CChatDGram();
pChatDGram->m_dwNetMsgID = dwNetMsgID;
pChatDGram->m_strMsg = strMsg;
//6. 发送消息给主窗口通知收到聊天报文。
pNetMsg->PostMessage(WM_CHAT_MSG, 0, (LPARAM)pChatDGram);
}
}
svrSocket.Close();
TRACE(_T("退出RecvService...\n"));
::CoUninitialize();
AfxEndThread(0);
return 0;
}
//##ModelId=3E3283360248
CChatDlg * CChatDlg::CreateFriendRelatedWnd(POSITION pos, DWORD dwPeerNetMsgID, CString strPeerNickName, CString strPeerIPAddress)
{
//1.生成聊天窗口
CChatDlg *pDlg = new CChatDlg();
//2.设置绑定参数。
pDlg->m_posPeer = pos;
pDlg->m_strPeerIPAddress = strPeerIPAddress;
pDlg->m_strPeerNickName = strPeerNickName;
pDlg->m_dwPeerNetMsgID = dwPeerNetMsgID;
pDlg->m_strSelfNickName = ((CNetMsgDlg *)AfxGetMainWnd())->get_SelfNickName();
pDlg->m_dwSelfNetMsgID = ((CNetMsgDlg *)AfxGetMainWnd())->get_SelfNetMsgID();
//3.显示窗口
pDlg->Create(IDD);
pDlg->ShowWindow(SW_SHOW);
//4.返回指针
return pDlg;
}
//##ModelId=3E32866E0030
LRESULT CChatDlg::OnFriendOffline(WPARAM wParam, LPARAM lParam)
{
//1. 断开与朋友结点的联系。
BreakRelationToFriend();
//2.发送下线消息给自己。
PostMessage(WM_FRIEND_MSG, OFFLINE, 0);
return 0;
}
//##ModelId=3E32E44C029A
short CChatDlg::shortChatPort = 0;
//##ModelId=3E32EC9F0397
void CChatDlg::OnSend()
{
UpdateData(TRUE); //得到用户的输入信息 m_strMsg
//1. 禁止发送按钮和输入编辑框
m_cmdSend.EnableWindow(FALSE);
m_edtMsg.EnableWindow(FALSE);
//2.发送信息
SendMsg();
//3.保存信息
SaveMsg();
//4.显示信息
//5.滚动到最后一行。
int nLen = m_edtChatHist.GetWindowTextLength();
m_edtChatHist.SetSel(nLen, nLen);
CString strTemp = m_strSelfNickName + ": " + m_strMsg + "\r\n";
m_edtChatHist.ReplaceSel(strTemp);
//6.清空输入框
m_strMsg = "";
UpdateData(FALSE);
}
//##ModelId=3E32FB880332
LRESULT CChatDlg::OnFriendMsg(WPARAM wParam, LPARAM lParam)
{
if (wParam == OFFLINE)
{
BreakRelationToFriend();
AfxMessageBox("朋友已经下线,窗口要关闭。");
DestroyWindow();
}
return 0;
}
//##ModelId=3E3302810176
void CChatDlg::SaveMsg(CString speaker, CString strMsg)
{
extern CNetMsgApp theApp; //Application
CString strFileName;
strFileName.Format((theApp.get_WorkDIR() + "chat\\%u"), m_dwPeerNetMsgID);
CString strPut = speaker + ": ";
strPut += strMsg + "\n";
try
{
CStdioFile file(strFileName, CFile::modeCreate
| CFile::modeNoTruncate
| CFile::modeWrite
| CFile::shareDenyWrite
| CFile::typeText);
file.SeekToEnd();
file.WriteString(strPut);
}
catch(CFileException &e)
{
e.ReportError();
}
}
//##ModelId=3E34420F0351
void CChatDlg::PostNcDestroy()
{
TRACE("正在删除与<%s>聊天的对话框。\n", m_strPeerNickName);
CNetMsgDlg *pMainWnd = static_cast<CNetMsgDlg *>(AfxGetMainWnd());
pMainWnd->CloseChatDlg(m_posPeer);
BreakRelationToFriend();
CDialog::PostNcDestroy();
delete this; //对于一个无模态的对话框必须要这样做。
}
//##ModelId=3E34420F0383
void CChatDlg::OnClose()
{
//CNetMsgDlg *pMainWnd = static_cast<CNetMsgDlg *>(AfxGetMainWnd());
//pMainWnd->CloseChatDlg(m_posPeer);
//BreakRelationToFriend();
DestroyWindow();
}
//##ModelId=3E34420F02E3
void CChatDlg::BreakRelationToFriend()
{
m_posPeer = NULL;
m_strPeerIPAddress = "";
m_strPeerNickName = "";
m_dwPeerNetMsgID = 0;
}
//##ModelId=3E3442200067
void CChatDlg::set_Peer(POSITION value)
{
m_posPeer = value;
return;
}
//##ModelId=3E3442310198
const POSITION& CChatDlg::get_Peer() const
{
return m_posPeer;
}
//##ModelId=3E361E2502AF
LRESULT CChatDlg::OnChatMsg(WPARAM wParam, LPARAM lParam)
{
m_cmdSend.EnableWindow();
m_edtMsg.EnableWindow();
m_edtMsg.SetFocus();
return 0;
}
//##ModelId=3E361E250309
void CChatDlg::OnDropFiles(HDROP hDropInfo)
{
//1. 现在只支持一个文件的 Dragdrop,如果用户拖了多个文件,那么就
//只对第一个文件操作。
int nLen = DragQueryFile(hDropInfo, 0, NULL, 0);
char *pFileName = new char[nLen + 1];
DragQueryFile(hDropInfo, 0, pFileName, nLen + 1);
//2. 检查文件是不是Directory
DWORD dwAttr = ::GetFileAttributes(pFileName);
if (dwAttr & FILE_ATTRIBUTE_DIRECTORY)
{
AfxMessageBox("目前不支持传送文件夹!");
}
else
{
//3. 询问用户是不是要传输这个文件<文件名>
CString strAlert;
strAlert = "您要传输文件: ";
strAlert += pFileName;
strAlert += "吗?";
AfxMessageBox(strAlert);
//4. 开始传输。
SendFile(pFileName);
}
//5. 释放Dragdrop的句柄
::DragFinish(hDropInfo);
delete []pFileName;
//CDialog::OnDropFiles(hDropInfo);
}
//##ModelId=3E431B0A03E0
void CChatDlg::OnFiletran()
{
CFileDialog dlg(TRUE);
if (IDOK == dlg.DoModal())
{
AfxMessageBox(dlg.m_ofn.lpstrFile);
SendFile(dlg.m_ofn.lpstrFile);
}
}
void CChatDlg::SendFile(CString strFileName)
{
CFileTranDlg::SENDER_PARAM *paramSend = new CFileTranDlg::SENDER_PARAM;
strcpy(paramSend->szServer, (const char *)m_strPeerIPAddress);
strcpy(paramSend->szFilePath, (const char *)strFileName);
paramSend->nFileSize = 0;
AfxBeginThread(CFileTranDlg::SendFileWorkProc, paramSend);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -