MFC 自定义 PostMessage 、SendMessage 消息
目录
一、PostMessage 和 SendMessage 描述
二、自定义窗体消息步骤(父子窗体传递消息、本窗体传递消息)
1.在全局头文件中 宏定义消息ID
2.在要响应动作的窗体类 头文件和源文件 声明和定义消息响应函数:
3.在源文件的消息映射添加自定义消息和响应函数的映射
4.消息发送
三、窗体的属性注意事项
四、拓展-项目窗体整体消息管理
一、PostMessage 和 SendMessage 描述
1.SendMessage 是同步的,它会阻塞调用线程,直到目标窗口处理完消息并返回结果。这意味着调用线程会等待消息处理完成后再继续执行。
2.PostMessage 是异步的,它将消息放入目标线程的消息队列后立即返回,不会等待消息处理完成。调用线程可以继续执行后续代码,而不关心消息是否被处理。
二、自定义窗体消息步骤(父子窗体传递消息、本窗体传递消息)
1.在全局头文件中 宏定义消息ID
/*
@基于 WM_USER 往上加, 其他自定义消息依次累加,自定义消息值不得相同/重复
*/
#define UM_MAINDLG_SHOW_DOMODAL WM_USER + 0x211 //
/********************************
@例子:
#define UM_MAINDLG_SHOW_DOMODAL WM_USER + 0x211
#define UM_MOUSE_RIGHT_KEY WM_USER + 0x211
*当上两个消息在同一个窗体的消息映射中:
.....
ON_MESSAGE(UM_MOUSE_RIGHT_KEY, &CPstParamDlg::OnSaveParam) //(1)
ON_MESSAGE(UM_MAINDLG_SHOW_DOMODAL, &CPstParamDlg::OnUmNotifyParent)
.....
UM_MAINDLG_SHOW_DOMODAL 消息会被 UM_MOUSE_RIGHT_KEY 捕获,导致 OnUmNotifyParent 没有响应
*******************************/
2.在要响应动作的窗体类 头文件和源文件 声明和定义消息响应函数:
//头文件.h 声明消息响应函数
afx_msg LRESULT OnUmShowDomodal(WPARAM wParam, LPARAM lParam);
//源文件 .cpp 定义消息响应函数
afx_msg LRESULT CMainDlg::OnUmShowDomodal(WPARAM wParam, LPARAM lParam)
{
int nType = (int)wParam; //解析发送过来的参数
switch (nType)
{
case 0:
{
break;
}
default:
break;
}
return 0;
}
3.在源文件的消息映射添加自定义消息和响应函数的映射
//源文件 .cpp
BEGIN_MESSAGE_MAP(CMainDlg, CDialogEx)
ON_WM_CTLCOLOR()
ON_WM_SHOWWINDOW()
ON_MESSAGE(UM_MOUSE_RIGHT_KEY, &CMainDlg::OnSaveParam) //会截获消息
//.
//.
ON_MESSAGE(UM_MAINDLG_SHOW_DOMODAL, &CMainDlg::OnUmShowDomodal) //增加自定义消息映射
END_MESSAGE_MAP()
4.消息发送
4.1 给本窗体自定义消息发送
void CMainDlg::SendMessageFunc()
{
*本窗体消息发送
PostMessage(UM_MAINDLG_SHOW_DOMODAL,0,0/*传送该值Type*/);
//::PostMessage(GetSafeWnd(),UM_MAINDLG_SHOW_DOMODAL,0,0/*传送该值Type*/);
//或
SendMessage(UM_MAINDLG_SHOW_DOMODAL,0,1/*传送该值Type*/);
//::SendMessage(GetSafeWnd(),UM_MAINDLG_SHOW_DOMODAL,0,0/*传送该值Type*/);
}
4.2 消息映射和消息响应函数在子窗体,父窗体通过 SendMessage 或 PostMessage 发送消息到子窗体:
//父窗体源文件 new 子窗体
std::vector
void CMainDlg::InitChildDlg()
{
m_vecChildDlg.push_back(new CChildDlg(......));
//....
//....
std::vector
for( ; it != m_vecChildDlg.end(); it++)
{
(*it)->Create(IDD_DIALOG_CHILD,this);
(*it)->ShowWindow(SW_NORMAL);
}
}
//父窗体发送消息给子窗体
void CMainDlg::SendMessageToChild()
{
std::vector
for( ; it != m_vecChildDlg.end(); it++)
{
/*
@发送消息 或用PostMessage
*/
(*it)->SendMessage(UM_NOTIFY_CHILD, NULL, 0);
}
}
/*
子窗体源文件接收并解析消息
ON_MESSAGE(UM_NOTIFY_CHILD, &CChildDlg::OnUmNotifyChild)
*/
afx_msg LRESULT CChildDlg::OnUmNotifyChild(WPARAM wParam, LPARAM lParam)
{
((CButton *)GetDlgItem(IDC_CHECK1))->SetCheck((int)lParam);
if (m_pnInitValue != nullptr)
{
*m_pnInitValue = (BOOL)lParam;
}
return 0;
}
4.3 消息映射以及消息响应函数在父窗体中,子窗体发送消息到父窗体:
//子窗体发送消息到上一层父窗体
void CChildDlg::OnBnClickedCheck1()
{
UpdateData(TRUE);
if (m_pnInitValue != nullptr)
{
*m_pnInitValue = m_nValue;
}
m_btnCheck.SetColor(RGB(255,255,255),m_colorEdit);
::SendMessage(GetParent()->GetSafeHwnd(), UM_NOTIFY_PARENT, (WPARAM)(static_cast
}
/*
父窗体接收并解析消息
ON_MESSAGE(UM_NOTIFY_PARENT, &CMainDlg::OnUmNotifyParent)
*/
afx_msg LRESULT CMainDlg::OnUmNotifyParent(WPARAM wParam, LPARAM lParam)
{
CDlgParam *pParam = (CDlgParam *)wParam;
CString ss = pParam->GetParamName();
if (pParam->GetParamName() == _T("子窗体1"))
{
if ((bool)lParam)
{
//.......
}
}
return 0;
}
三、窗体的属性注意事项
1.以上步骤完成后,消息函数依旧没有响应,除了可以考虑消息可能被其他消息映射截获的异常,还可以查看窗体的 ' No Parent Notifly ' 窗体属性是否屏蔽了消息响应。
四、拓展-项目窗体整体消息管理
1.基于综上知识点,可以将项目里面的所有窗体消息集中管理,可以在需要的地方给对象窗体发送需要的消息数据等。思路如下:
1.1声明全局静态窗体消息管理类:
//Global.h
#include
#include
#define DlgMsgCtrl (WM_USER + 210) //自定义消息
class CInfoControl
{
private:
CInfoControl();
~CInfoControl();
static std::mutex m_mutex; //
static std::vector
public:
static void AddCwndInfo(HWND pWnd); //每一个窗体初始化 OnInitDialog() 的时候将窗体注册进去
static void SendInfo(CString strType, CString strMsg); //将消息向注册的窗体群发,每个窗体消息里面可以做自己的消息标志过滤;
};
1.2 窗体消息管理类实现:
#include "pch.h"
#include "Global.h"
#include
#include
CInfoControl::CInfoControl()
{
}
CInfoControl::~CInfoControl()
{
}
std::mutex CInfoControl::m_mutex;
std::vector
void CInfoControl::AddCwndInfo(HWND pWnd)
{
std::lock_guard
if (pWnd != nullptr)
{
for (int i = 0; i < m_vecCWnd.size(); i++)
{
if (m_vecCWnd[i] == pWnd)
{
return;
}
}
m_vecCWnd.push_back(pWnd);
}
return;
}
void CInfoControl::SendInfo(CString strType,CString strMsg)
{
std::lock_guard
for (int i = 0 ; i < m_vecCWnd.size() ; i++)
{
if (m_vecCWnd[i] != nullptr)
{
::SendMessage(m_vecCWnd[i],DlgMsgCtrl,(WPARAM)strType.GetBuffer(),(LPARAM)strMsg.GetBuffer());
}
}
return;
}
2.某一窗体的实现:
//.h 声明消息响应函数
afx_msg LRESULT InfoMsg(WPARAM wParam, LPARAM lParam);
//.cpp
//增加消息映射
ON_MESSAGE(DlgMsgCtrl,&CMFCApplication2Dlg::InfoMsg)
//增加响应函数实现
afx_msg LRESULT CMFCApplication2Dlg::InfoMsg(WPARAM wParam, LPARAM lParam)
{
CString strType = (TCHAR *)wParam;
CString strMsg = (TCHAR *)lParam;
//....消息过滤
//....消息处理
return 0;
}
//任意地方发送消息 群发消息
void CMFCApplication2Dlg::OnBnClickedButton1()
{
CInfoControl::SendInfo(_T("ERROR_SHOW"),_T("DLG_1::群发消息,需要的窗体做标志过滤"));
return;
}