⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 chatdlg.cpp

📁 本人买的<<VC++项目开发实例>>源代码配套光盘.
💻 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 + -