创建群
数据库 group_table(user, name)
grpuser_table(grpname,user)
按下添加群按钮
// 创建群组
void CUserDialog::OnBnClickedCrtgrp()
{
// 1. 获取群的名字,和自己的名字
UpdateData(TRUE);
CString MyName = MainDialog->m_UserName;
// 2. 组合结构体
SEND_INFO SendInfo = { TYPE::CRTGRP, GetSafeHwnd() };
memcpy(SendInfo.CrtGrpInfo.Creator, MyName.GetBuffer(), MyName.GetLength() * 2);
memcpy(SendInfo.CrtGrpInfo.GrpName, m_AddEdit.GetBuffer(), m_AddEdit.GetLength() * 2);
// 3. 发送消息到服务器
::SendMessage(MainDialog->GetSafeHwnd(), UM_SEND_MSG, (WPARAM)& SendInfo, sizeof(SendInfo));
}
所需结构体
// 5. 建群消息
typedef struct _CRTGRP_INFO
{
WCHAR Creator[32];
WCHAR GrpName[32];
} CRTGRP_INFO, * PCRTGRP_INFO;
服务器接收处理并返回
客户端主窗口接收到并转发
// 响应建群
case TYPE::CRTGRP:
{
// 对于注册是否成功的消息,wParam 没有用,lParam 指向 RECV_STATE
::SendMessage(RecvInfo->hWnd, UM_RECV_CRTGRP, NULL, (LPARAM)& RecvInfo->RecvState);
break;
}
// 建群
afx_msg LRESULT CUserDialog::OnUmRecvCrtgrp(WPARAM wParam, LPARAM lParam)
{
// 将 lParam 转换成对应的的结构
PRECV_STATE RecvState = (PRECV_STATE)lParam;
// 判断是否添加成功
if (RecvState->IsSuccess)
{
// 如果成功执行直接添加到列表
m_TreeCtrl.InsertItem(&RecvState->MsgInfo[0], m_GrpNode);
return 0;
}
// 不成功执行这里
MessageBox(RecvState->MsgInfo);
return 0;
}
添加群组
按下添加按钮
// 添加群组
void CUserDialog::OnBnClickedAddgrp()
{
// 1. 获取群的名字,和自己的名字
UpdateData(TRUE);
CString MyName = MainDialog->m_UserName;
// 2. 组合结构体
SEND_INFO SendInfo = { TYPE::ADDGRP, GetSafeHwnd() };
memcpy(SendInfo.AddGrpInfo.User, MyName.GetBuffer(), MyName.GetLength() * 2);
memcpy(SendInfo.AddGrpInfo.Group, m_AddEdit.GetBuffer(), m_AddEdit.GetLength() * 2);
// 3. 发送消息到服务器
::SendMessage(MainDialog->GetSafeHwnd(), UM_SEND_MSG, (WPARAM)& SendInfo, sizeof(SendInfo));
}
所需结构体
// 6. 添加群组的消息
typedef struct _ADDGRP_INFO
{
WCHAR User[32];
WCHAR Group[32];
} ADDGRP_INFO, * PADDGRP_INFO;
服务器
客户端
// 响应加群
case TYPE::ADDGRP:
{
// 对于注册是否成功的消息,wParam 没有用,lParam 指向 RECV_STATE
::SendMessage(RecvInfo->hWnd, UM_RECV_ADDGRP, NULL, (LPARAM)& RecvInfo->RecvState);
break;
}
// 加群
afx_msg LRESULT CUserDialog::OnUmRecvAddgrp(WPARAM wParam, LPARAM lParam)
{
// 将 lParam 转换成对应的的结构
PRECV_STATE RecvState = (PRECV_STATE)lParam;
// 判断是否添加成功
if (RecvState->IsSuccess)
{
// 如果成功执行直接添加到列表
m_TreeCtrl.InsertItem(&RecvState->MsgInfo[1], m_GrpNode);
return 0;
}
// 不成功执行这里
MessageBox(RecvState->MsgInfo);
return 0;
}
更新群组列表
初始化的时候发送请求
// 发消息给服务器更新好友列表
SEND_INFO SendInfo1 = { TYPE::UPDATEGRP, GetSafeHwnd() };
memcpy(SendInfo1.UpdateGrpInfo.Name, MainDialog->m_UserName.GetBuffer(),
MainDialog->m_UserName.GetLength() * 2);
// 通过主窗口向服务器发送消息
::SendMessage(MainDialog->GetSafeHwnd(), UM_SEND_MSG, (WPARAM)& SendInfo1, sizeof(SendInfo));
相关的结构体
// 7. 更新群组列表
typedef struct _UPDATEGRP_INFO
{
WCHAR Name[32];
} UPDATEGRP_INFO, * PUPDATEGRP_INFO;
服务器接收到处理之后发回来
客户端接受到消息之后处理
主窗口响应,转发
// 响应加群
case TYPE::UPDATEGRP:
{
// 对于注册是否成功的消息,wParam 没有用,lParam 指向 RECV_STATE
::SendMessage(RecvInfo->hWnd, UM_RECV_UPDATEGRP, NULL, (LPARAM)& RecvInfo->UpdateGrpInfo);
break;
}
转发到的地方
// 更新群组
afx_msg LRESULT CUserDialog::OnUmRecvUpdategrp(WPARAM wParam, LPARAM lParam)
{
// 转换成对应的结构体
PUPDATEGRP_INFO GrpInfo = (PUPDATEGRP_INFO)lParam;
// 【添加到树控件的好友节点中,收到的消息前两个字节会是 ff fe】
m_TreeCtrl.InsertItem(&GrpInfo->Name[1], m_GrpNode);
return 0;
}
群聊
双击树控件的时候跳出群聊框 参考好友
点击发送发送信息
void CGrpDialog::OnBnClickedSendmsg()
{
// 1. 获取编辑框(聊天记录 + 输入框)的内容
UpdateData(TRUE);
// 2. 将用户的输入拼接到聊天框的结尾
SYSTEMTIME SystemTime = { 0 };
GetSystemTime(&SystemTime);
CString TimeString;
TimeString.Format(L"%d:%d:%d %d:%d:%d", SystemTime.wYear,
SystemTime.wMonth, SystemTime.wDay, SystemTime.wHour,
SystemTime.wMinute, SystemTime.wSecond);
m_ShowEdit += L"你 说(" + TimeString + L"):
"
+ m_InputEdit + L"
";
// 3. 将输入的数据进行组合,句柄是无效的
CString MyName = MainDialog->m_UserName;
SEND_INFO SendInfo = { TYPE::GRPMSG, NULL };
memcpy(SendInfo.GrpMsg.From, MyName.GetBuffer(), MyName.GetLength() * 2);
memcpy(SendInfo.GrpMsg.To, m_TargetName.GetBuffer(), m_TargetName.GetLength() * 2);
memcpy(SendInfo.GrpMsg.Msg, m_InputEdit.GetBuffer(), m_InputEdit.GetLength() * 2);
// 4. 通过主窗口发送到服务器
::SendMessage(MainDialog->GetSafeHwnd(), UM_SEND_MSG, (WPARAM)& SendInfo, sizeof(SEND_INFO));
// 5. 将组合的数据显示到输出框
m_InputEdit = "";
UpdateData(FALSE);
}
所需结构体
// 8. 群组消息
using GRPMSG_INFO = FRDMSG_INFO;
using PGRPMSG_INFO = PFRDMSG_INFO;
服务器接收到信息处理并发送回来
def on_grpmsg(self, client, message):
客户端
case TYPE::GRPMSG:
{
// 1. 获取群组的名字,To 保存的是发送给具体的群
CString Name = RecvInfo->FrdMsg.To;
// 2. 判断有没有窗口标题为这个名字的窗口
if (WindowsMap.find(Name) == WindowsMap.end())
{
// 3. 如果没有这个窗口就进行创建
CGrpDialog* dialog = new CGrpDialog(Name);
dialog->Create(IDD_DIALOG3, this);
// 3.2.2 设置群聊天窗口的窗口名为群名
dialog->SetWindowText(Name);
dialog->ShowWindow(SW_SHOWNORMAL);
// 3.2.3 将新创建的窗口添加到字典中
WindowsMap[Name] = dialog;
}
// 4. 发送给对应的窗口
::SendMessage(WindowsMap[Name]->GetSafeHwnd(), UM_RECV_GRPMSG, NULL, (LPARAM)& RecvInfo->FrdMsg);
break;
}
afx_msg LRESULT CGrpDialog::OnUmRecvGrpmsg(WPARAM wParam, LPARAM lParam)
{
// 0. 转换成对应的结构体
PGRPMSG_INFO Msg = (PGRPMSG_INFO)lParam;
// 1. 获取编辑框(聊天记录)的内容
UpdateData(TRUE);
// 2. 将用户的输入拼接到聊天框的结尾
SYSTEMTIME SystemTime = { 0 };
GetSystemTime(&SystemTime);
CString TimeString;
TimeString.Format(L"%d:%d:%d %d:%d:%d", SystemTime.wYear,
SystemTime.wMonth, SystemTime.wDay, SystemTime.wHour,
SystemTime.wMinute, SystemTime.wSecond);
m_ShowEdit += CString(Msg->From) + L" 说(" + TimeString + L"):
"
+ Msg->Msg + L"
";
// 3. 将组合的数据显示到输出框
UpdateData(FALSE);
return 0;