MFC框架中WM_COMMAND訊息響應順序
在MFC開發的程式中,選單、工具條按鈕等都會產生WM_COMMAND訊息。而在MFC的Document/View框架中,有很多類可以響應WM_COMMAND訊息,分別是框架類:CFrameWnd、CMDIChildWnd、CMDIFrameWnd;應用程式類CWinApp;文件類CDocument;以及檢視類CView。
當應用程式主選單傳送了一個WM_COMMAND訊息時,WM_COMMAND訊息將會按一定順序被交這些類的例項,並呼叫第一個發現的響應函式。以多文件檢視框架應用程式為例,我們可以分析MFC中這些類的原始碼,並一步一步找出WM_COMMAND訊息的響應順序。
因為框架視窗是選單的父視窗,所以訊息首先發到CMDIFrameWnd類的例項(也就是主框架視窗,通常為CMainFrame)。CMDIFrameWnd類的OnCmdMsg函式如下:
BOOL CMDIFrameWnd::OnCmdMsg(UINT nID, int nCode, void* pExtra,
AFX_CMDHANDLERINFO* pHandlerInfo)
{
CMDIChildWnd* pActiveChild = MDIGetActive();
// pump through active child FIRST
if (pActiveChild != NULL)
{
CPushRoutingFrame push(this);
if (pActiveChild->OnCmdMsg(nID, nCode, pExtra, pHandlerInfo))
return TRUE;
}
// then pump through normal frame
return CFrameWnd::OnCmdMsg(nID, nCode, pExtra, pHandlerInfo);
}
AFX_CMDHANDLERINFO* pHandlerInfo)
{
CMDIChildWnd* pActiveChild = MDIGetActive();
// pump through active child FIRST
if (pActiveChild != NULL)
{
CPushRoutingFrame push(this);
if (pActiveChild->OnCmdMsg(nID, nCode, pExtra, pHandlerInfo))
return TRUE;
}
// then pump through normal frame
return CFrameWnd::OnCmdMsg(nID, nCode, pExtra, pHandlerInfo);
}
子框架視窗CMDIChildWnd > 主框架視窗CMDIFrameWnd
CMDIChildWnd視窗沒有過載OnCmdMsg函式,所以使用基本框架視窗CFrameWnd的OnCmdMsg函式:
BOOL CFrameWnd::OnCmdMsg(UINT nID, int nCode, void* pExtra,
AFX_CMDHANDLERINFO* pHandlerInfo)
{
CPushRoutingFrame push(this);
// pump through current view FIRST
CView* pView = GetActiveView();
if (pView != NULL && pView->OnCmdMsg(nID, nCode, pExtra, pHandlerInfo))
return TRUE;
// then pump through frame
if (CWnd::OnCmdMsg(nID, nCode, pExtra, pHandlerInfo))
return TRUE;
// last but not least, pump through app
CWinApp* pApp = AfxGetApp();
if (pApp != NULL && pApp->OnCmdMsg(nID, nCode, pExtra, pHandlerInfo))
return TRUE;
return FALSE;
}
AFX_CMDHANDLERINFO* pHandlerInfo)
{
CPushRoutingFrame push(this);
// pump through current view FIRST
CView* pView = GetActiveView();
if (pView != NULL && pView->OnCmdMsg(nID, nCode, pExtra, pHandlerInfo))
return TRUE;
// then pump through frame
if (CWnd::OnCmdMsg(nID, nCode, pExtra, pHandlerInfo))
return TRUE;
// last but not least, pump through app
CWinApp* pApp = AfxGetApp();
if (pApp != NULL && pApp->OnCmdMsg(nID, nCode, pExtra, pHandlerInfo))
return TRUE;
return FALSE;
}
存在開啟的檢視時,檢視CView > 子框架CFrame > 應用程式CWinApp >主框架視窗CMDIFrameWnd
沒有開啟檢視時,主框架視窗CMDIFrameWnd > 應用程式CWinApp
再看檢視CView類對OnCmdMsg的處理:
BOOL CView::OnCmdMsg(UINT nID, int nCode, void* pExtra,
AFX_CMDHANDLERINFO* pHandlerInfo)
{
// first pump through pane
if (CWnd::OnCmdMsg(nID, nCode, pExtra, pHandlerInfo))
return TRUE;
// then pump through document
if (m_pDocument != NULL)
{
// special state for saving view before routing to document
CPushRoutingView push(this);
return m_pDocument->OnCmdMsg(nID, nCode, pExtra, pHandlerInfo);
}
return FALSE;
}
AFX_CMDHANDLERINFO* pHandlerInfo)
{
// first pump through pane
if (CWnd::OnCmdMsg(nID, nCode, pExtra, pHandlerInfo))
return TRUE;
// then pump through document
if (m_pDocument != NULL)
{
// special state for saving view before routing to document
CPushRoutingView push(this);
return m_pDocument->OnCmdMsg(nID, nCode, pExtra, pHandlerInfo);
}
return FALSE;
}
檢視CView > 文件CDocument > 子框架CFrame > 應用程式CWinApp >主框架視窗CMDIFrameWnd
再檢視CDocument的OnCmdMsg的實現程式碼:
BOOL CDocument::OnCmdMsg(UINT nID, int nCode, void* pExtra,
AFX_CMDHANDLERINFO* pHandlerInfo)
{
if (CCmdTarget::OnCmdMsg(nID, nCode, pExtra, pHandlerInfo))
return TRUE;
// otherwise check template
if (m_pDocTemplate != NULL &&
m_pDocTemplate->OnCmdMsg(nID, nCode, pExtra, pHandlerInfo))
return TRUE;
return FALSE;
}
AFX_CMDHANDLERINFO* pHandlerInfo)
{
if (CCmdTarget::OnCmdMsg(nID, nCode, pExtra, pHandlerInfo))
return TRUE;
// otherwise check template
if (m_pDocTemplate != NULL &&
m_pDocTemplate->OnCmdMsg(nID, nCode, pExtra, pHandlerInfo))
return TRUE;
return FALSE;
}
BOOL CDocTemplate::OnCmdMsg(UINT nID, int nCode, void* pExtra,
AFX_CMDHANDLERINFO* pHandlerInfo)
{
BOOL bReturn;
CCmdTarget* pFactory = DYNAMIC_DOWNCAST(CCmdTarget, m_pAttachedFactory);
if (nCode == CN_OLE_UNREGISTER && pFactory != NULL)
bReturn = pFactory->OnCmdMsg(nID, nCode, pExtra, pHandlerInfo);
else
bReturn = CCmdTarget::OnCmdMsg(nID, nCode, pExtra, pHandlerInfo);
return bReturn;
}
AFX_CMDHANDLERINFO* pHandlerInfo)
{
BOOL bReturn;
CCmdTarget* pFactory = DYNAMIC_DOWNCAST(CCmdTarget, m_pAttachedFactory);
if (nCode == CN_OLE_UNREGISTER && pFactory != NULL)
bReturn = pFactory->OnCmdMsg(nID, nCode, pExtra, pHandlerInfo);
else
bReturn = CCmdTarget::OnCmdMsg(nID, nCode, pExtra, pHandlerInfo);
return bReturn;
}
事實上在多文件框架中,系統自動生成的程式碼使用的是CDocTemplate的子類CMultiDocTemplate。在應用程式類(多文件應用框架)的InitInstance()裡可以找到類似下面的程式碼:
// 註冊應用程式的文件模板。文件模板
// 將用作文件、框架視窗和檢視之間的連線
CMultiDocTemplate* pDocTemplate;
pDocTemplate = new CMultiDocTemplate(IDR_test3TYPE,
RUNTIME_CLASS(Ctest3Doc),
RUNTIME_CLASS(CChildFrame), // 自定義 MDI 子框架
RUNTIME_CLASS(Ctest3View));
if (!pDocTemplate)
return FALSE;
// 將用作文件、框架視窗和檢視之間的連線
CMultiDocTemplate* pDocTemplate;
pDocTemplate = new CMultiDocTemplate(IDR_test3TYPE,
RUNTIME_CLASS(Ctest3Doc),
RUNTIME_CLASS(CChildFrame), // 自定義 MDI 子框架
RUNTIME_CLASS(Ctest3View));
if (!pDocTemplate)
return FALSE;
通過分析MFC的原始碼,我們可以得到WM_COMMAND的訊息響應順序如下:
多文件框架中,有開啟的文件時:檢視 > 文件 > 子框架視窗 > 應用程式 >主框架視窗
多文件框架在沒有開啟文件時,應用程式和主框架視窗的順序相反:主框架視窗 > 應用程式
在單文件框架應用程式中,因為沒有子框架視窗,所以順序應該是:檢視 > 文件 >主框架視窗> 應用程式。無論有沒有開啟文件,主框架視窗都比應用程式類更優先。
作者:蘇林
相關文章
- MFC應用程式中處理訊息的順序
- 深入解析MFC訊息響應和訊息路由路由
- MFC訊息響應機制分析 (轉)
- 解析 RocketMQ 業務訊息--“順序訊息”MQ
- mfc中的訊息的應用 (轉)
- 關於RocketMQ的順序訊息MQ
- 分散式訊息佇列:如何保證訊息的順序性分散式佇列
- 如何保證訊息佇列的順序性?佇列
- RocketMq如何順序消費的訊息offestMQ
- django中“url對映規則”和“服務端響應順序”Django服務端
- VC自定義訊息postmessage用法(訊息響應函式)函式
- 分散式訊息系統如何解決訊息的順序&重複兩大硬傷?分散式
- RMQ——支援合併和優先順序的訊息佇列MQ佇列
- RabbitMQ多消費者順序性消費訊息實現MQ
- Kafka 如何保證訊息消費的全域性順序性Kafka
- MFC學習(四) 訊息機制
- 個推百億級訊息推送的優先順序解決方案
- MFC 訊息對映機制詳解
- 順序表應用5:有序順序表歸併
- 順序表應用6:有序順序表查詢
- OCX 控制元件主動傳送訊息給 MFC 視窗訊息控制元件
- 記一次RocketMQ消費非順序訊息引起的線上事故MQ
- 阿里二面:Kafka中如何保證訊息的順序性?這周被問到兩次了阿里Kafka
- motorola手機中在主類中響應其它類中的按鈕訊息 (轉)
- JS控制音訊順序播放JS音訊
- MFC vc++ 中CTreeContrl如何自定義實現滑鼠單擊或雙擊響應事件 ,即重寫類似於控制元件的響應事件或訊息C++事件控制元件
- Java框架學習順序是哪些Java框架
- Java框架學習順序是哪些?Java框架
- 中斷優先順序
- Modbus通訊協議中的四種位元組順序協議
- MFC框架框架
- 關於MQ的幾件小事(五)如何保證訊息按順序執行MQ
- 交貨處理可能不需要順序,因為訊息順序處理和伸縮性是很難平衡的 - particular
- 快速掌握RabbitMQ(三)——訊息確認、持久化、優先順序的C#實現MQ持久化C#
- AIX主機名|IP 解析順序及影響AI
- AIX主機|IP 稱解析順序及影響AI
- JAVA中取順序號 (轉)Java
- 用MFC構造DirectX應用框架 (轉)框架