前提:
1.Socket通信
2.MFC窗口
主要应用场景:Socket传递的数据过多,处理不及引起堵塞,最终导致响应慢的情况,可尝试使用该方法。
1.创建一个类用来注册消息
#pragma once
class CSrvCommThd;
class CCmdWnd
{
public:
CCmdWnd(void);
~CCmdWnd(void);
BOOL RegisterRptMsgFromSrvRecvWnd(HWND hWnd,INT iRcvMsgType);//注册SrvSocket线程中的处理的消息。
private:
HWND m_hWndRcvCmd;
};
#include "stdafx.h"
#include "CmdMan.h"
#include "SrvSocket.h"
#include "主文件.h"
CCmdWnd::CCmdWnd(void)
{
//m_pSrvSocket = NULL;
}
CCmdWnd::~CCmdWnd(void)
{
if (theApp.m_pSrvSocket)
{
theApp.m_pSrvSocket->DeRegisterRptMsgRcvWnd(m_hWndRcvCmd);
}
}
BOOL CCmdWnd::RegisterRptMsgFromSrvRecvWnd(HWND hWnd,INT iRcvMsgType)
{
if (hWnd == NULL)
{
return FALSE;
}
m_hWndRcvCmd = hWnd;
if (theApp.m_pSrvSocket)
{
theApp.m_pSrvSocket->RegisterRptMsgRcvWnd(hWnd,iRcvMsgType);
}
return TRUE;
}
2.在SvrSocket线程中添加注册/注销函数用于注册/注销窗口事件
2.1 SvrSocket头文件注意要包含"CmdMan.h",在类中添加下列代码
std::map<HWND,UINT>m_mapBroadcastWnd;
std::set<pair<HWND, DWORD> > m_CmdWndVec;
BOOL RegisterRptMsgRcvWnd(HWND hWnd,INT iRcvType = 1);
BOOL BBMSRegisterRptMsgRcvWnd(HWND hWnd, INT iRcvType = 1);
2.2 SvrSocket源文件
BOOL CSrvSocket::RegisterRptMsgRcvWnd(HWND hWnd,int iRcvType)
{
m_mapBroadcastWnd[hWnd]=iRcvType;
m_CmdWndVec.insert(make_pair(hWnd, iRcvType));
return TRUE;
}
void CSrvSocket:: DeRegisterRptMsgRcvWnd(HWND hWnd)
{
if (m_mapBroadcastWnd.find(hWnd)!= m_mapBroadcastWnd.end())
{
m_stackhWndClosed.push(hWnd);
}
}
3 在窗口初始化函数OnInitDialog()中进行注册
RegisterRptMsgFromSrvRecvWnd(GetSafeHwnd(), CMD_1);
RegisterRptMsgFromSrvRecvWnd(GetSafeHwnd(), CMD_2);
GetSafeHwnd()
是MFC框架中的一个成员函数,用于获取窗口的句柄(handle)。它的作用是返回一个有效的窗口句柄,如果窗口尚未创建或已经销毁,则返回NULL
。
窗口句柄是一个唯一标识窗口的整数值,它在操作系统层面用于识别和管理窗口。通过窗口句柄,可以对窗口进行各种操作,如发送消息、改变窗口属性等。
在MFC框架中,每个派生自CWnd
类的窗口类都具有一个GetSafeHwnd()
成员函数。这个函数可以在窗口对象中调用,以获取该窗口的句柄。
GetSafeHwnd()
函数的使用场景包括:
- 在窗口类的成员函数中需要访问窗口句柄时,可以使用
GetSafeHwnd()
来获取句柄。 - 在消息处理函数中需要将窗口句柄传递给其他函数或API时,可以使用
GetSafeHwnd()
来获取句柄。 - 在需要判断窗口是否有效的情况下,可以使用
GetSafeHwnd()
来检查窗口句柄是否为NULL
。
需要注意的是,GetSafeHwnd()
函数是为了安全起见而设计的。在MFC中,如果窗口对象已经被销毁,直接使用GetHwnd()
可能会导致程序崩溃或其他错误。而使用GetSafeHwnd()
可以避免这种情况,它会在窗口对象已经销毁时返回NULL
,以避免访问无效的句柄。
4.给一个窗口进行消息映射处理
BEGIN_MESSAGE_MAP(CDlg, CBaseDialog)
ON_MESSAGE(WM_USER_RECV_MSG, &CDlg::OnStnClickedStaticLogo)
END_MESSAGE_MAP()
ON_MESSAGE
是MFC框架中的一个宏,用于将消息映射到消息处理函数。
在MFC中,窗口类可以通过重写消息处理函数来处理各种消息,例如鼠标点击、键盘输入等。但是,对于一些自定义的消息或者系统消息,MFC框架并没有提供对应的虚函数供开发者重写。这时,就可以使用ON_MESSAGE
宏来将消息映射到一个特定的消息处理函数。
ON_MESSAGE
宏的语法如下:
ON_MESSAGE(message, memberFxn)
其中,message
是要映射的消息类型,可以是任何有效的消息值,如WM_USER
、WM_COMMAND
等。memberFxn
是一个消息处理函数的名称,它必须是窗口类的成员函数,并且具有特定的签名。
使用ON_MESSAGE
宏可以实现以下功能:
- 将自定义消息或系统消息映射到特定的消息处理函数,以便在收到该消息时执行相应的逻辑。
- 扩展MFC框架的消息处理能力,处理一些MFC框架本身没有提供的消息。
使用ON_MESSAGE
宏的步骤如下:
- 在窗口类的消息映射表中添加一条映射项,指定要映射的消息和消息处理函数。
- 在窗口类中定义消息处理函数,并按照特定的签名编写函数体。
示例代码如下:
BEGIN_MESSAGE_MAP(CMyWnd, CWnd)
ON_MESSAGE(WM_MY_CUSTOM_MESSAGE, OnMyCustomMessage)
END_MESSAGE_MAP()
LRESULT CMyWnd::OnMyCustomMessage(WPARAM wParam, LPARAM lParam)
{
// 处理自定义消息的逻辑
// ...
return 0;
}
在上述示例中,WM_MY_CUSTOM_MESSAGE
是一个自定义消息,通过ON_MESSAGE
宏将该消息映射到OnMyCustomMessage
函数,当窗口接收到该消息时,将调用OnMyCustomMessage
函数进行处理。
总而言之,ON_MESSAGE
宏是MFC框架中用于将消息映射到消息处理函数的一种机制,可以扩展MFC框架的消息处理能力,处理自定义消息或系统消息。
5.在OnStnClickedStaticLogo函数中添加处理
LRESULT CDlg::OnStnClickedStaticLogo(WPARAM dwCmdCode, LPARAM lpAppFrame)
{
if (lpAppFrame == NULL)
{
return FALSE;
}
stAppFrame* pAppFrame = (stAppFrame*)lpAppFrame;
/*FunSrvHandleCmd pFun = NULL;
pFun = m_msgHandleFunc[dwCmdCode];*/
switch (dwCmdCode)
{
case CMD_LOG_IN_RSP:
HandleCtrl1(pAppFrame);
break;
case PBBADS_CMD_CONTROL_REQ:
HandleCtrl2(pAppFrame);
break;
default:
break;
}
delete[](stAppFrame*)pAppFrame;
return TRUE;
}
6. 在Socket接收函数中分发信息命令
for (auto& itrCmdWnd : m_CmdWndVec)
{
if(itrCmdWnd.second == pAppFrame->dwCmdCode)
{
::PostMessage(itrCmdWnd.first, WM_USER_RECV_MSG, (WPARAM)pAppFrame->dwCmdCode, (LPARAM)pAppFrame);//分发服务器任务至窗口进行异步处理
}
}
-
PostMessage
函数:该函数是Windows API中的一个函数,用于向指定的窗口发送一个消息。它的函数原型如下:BOOL PostMessage( HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam );
其中,
hWnd
参数指定要接收消息的窗口句柄;Msg
参数指定要发送的消息类型;wParam
和lParam
参数分别是消息的两个参数,可以用来传递一些数据。 -
itrCmdWnd.first
:这是一个迭代器,指向一个std::pair
对象,该对象包含一个窗口句柄和一个布尔值。itrCmdWnd.first
表示该std::pair
对象的第一个元素,即窗口句柄。 -
WM_USER_RECV_MSG
:这是一个自定义的消息类型,它是一个整数值,通常定义在头文件中。在这里,它表示要发送的消息类型是接收到一个消息。 -
pAppFrame->dwCmdCode
:这是一个无符号整数值,表示要传递给窗口的消息参数之一。在这里,它表示接收到的消息的命令码。 -
pAppFrame
:这是一个指向应用程序框架对象的指针,它包含了要传递给窗口的消息参数之一。在这里,它表示接收到的消息帧。
这段代码的作用是向指定的窗口发送一个自定义消息,告诉窗口接收到了一个消息,并将消息的一些参数传递给该窗口。
总结:
为提高软件的响应速度,可采用异步处理的方式对消息进行处理,还可以一定程度上降低Socket堵塞的概率。
抽象:
(程序初始化时)
Socket:“窗口,我可能忙不过来,你来注册一下,搭把手。”
窗口:“行,我注册一下,用ON_MESSAGE进行了消息映射,你来活了丢给我就行,你好好跑腿XD~”
Socket:“我用::PostMessage丢给你,触发ON_MESSAGE,多谢兄弟,完事请你吃代码~”