再见,BEGIN_MSG_MAP!






3.46/5 (17投票s)
2005年5月28日
2分钟阅读

72388

384
使用 Boost.MPL 库来替代 BEGIN_MSG_MAP 宏。
前言
四年前,我编写了一个程序。 除了 Win32 薄封装器之外,WTL 原本拥有的东西都没用。 由于 CUpdateUI
是其中之一,我通过宏进行了替换。 后来,我读了《C++ 模板元编程》这本书,并受到了示例代码(有限状态机)的启发。 这可以删除宏,结果被命名为 ketchup,旨在取代 ATL/WTL 的 BEGIN_MSG_MAP
。
随着时间的推移,制作 biscuit 的经验让我能够避免编译时崩溃。 现在,ketchup 是 BEGIN_MSG_MAP
的类型安全同义词,可以帮助 WTL 赶上现代编程的步伐。
引言
Ketchup 是一个使用类模板实现的message map生成器。 这些模板允许我们编写类型安全的 BEGIN_MSG_MAP
。
一个简单的 BEGIN_MSG_MAP
宏片段
BEGIN_MSG_MAP(CMainFrame) MESSAGE_HANDLER(WM_CREATE, OnCreate) COMMAND_ID_HANDLER(ID_APP_EXIT, OnFileExit) COMMAND_ID_HANDLER(ID_FILE_NEW, OnFileNew) COMMAND_ID_HANDLER(ID_APP_ABOUT, OnAppAbout) CHAIN_MSG_MAP(WTL::CFrameWindowImpl<CMainFrame>) END_MSG_MAP()
使用 Ketchup 的功能可以近似实现,如本代码片段所示
begin_msg_map < message_handler<WM_CREATE, &_::OnCreate>, command_id_handler<ID_APP_EXIT, &_::OnFileExit>, command_id_handler<ID_FILE_NEW, &_::OnFileNew>, command_id_handler<ID_APP_ABOUT, &_::OnAppAbout>, chain_msg_map< WTL::CFrameWindowImpl<CMainFrame> > > end_msg_map;
要求
Microsoft Visual C++ .NET 版本 7.1, WTL 7.5 和 Boost C++ 库 (无需构建)。 我在带有 Visual C++ 工具包 2003 的 Visual C++ .NET 标准版中测试了演示。 Ketchup 本身是一个仅标头模板库。
快速入门
- 包含一个标头并从
ketchup::message_processor<CMainFrame>
派生#include "ketchup/ketchup.hpp" class CMainFrame : public WTL::CFrameWindowImpl<CMainFrame>, public WTL::CUpdateUI<CMainFrame>, public WTL::CMessageFilter, public WTL::CIdleHandler, public ketchup::message_processor<CMainFrame> {
- 定义消息处理程序
private: LRESULT OnCreate(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/) { // create command bar window HWND hWndCmdBar = m_CmdBar.Create(m_hWnd, rcDefault, NULL, ATL_SIMPLE_CMDBAR_PANE_STYLE); // attach menu m_CmdBar.AttachMenu(GetMenu()); // ... } // ...
- 让
CMainFrame
成为一个 message mappublic: begin_msg_map < message_handler<WM_CREATE, &_::OnCreate>, command_id_handler<ID_APP_EXIT, &_::OnFileExit>, command_id_handler<ID_FILE_NEW, &_::OnFileNew>, command_id_handler<ID_VIEW_TOOLBAR, &_::OnViewToolBar>, command_id_handler<ID_VIEW_STATUS_BAR, &_::OnViewStatusBar>, command_id_handler<ID_APP_ABOUT, &_::OnAppAbout>, chain_msg_map< WTL::CUpdateUI<CMainFrame> >, chain_msg_map< WTL::CFrameWindowImpl<CMainFrame> > > end_msg_map;
- 最后,像
BEGIN_MSG_MAP
偷偷做的那样,重写CMessageMap::ProcessWindowMessage
,使用ketchup::message_processor<CMainFrame>
提供的process_window_message
virtual BOOL ProcessWindowMessage(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT& lResult, DWORD dwMsgMapID = 0) { return process_window_message(hWnd, uMsg, wParam, lParam, lResult, dwMsgMapID); } };
请记住,消息处理程序的声明应放置在条目之前,并且 C++ 标准不允许您缩写成员函数指针的语法。
关注点
最后一点是性能。程序大小似乎不是问题。 VC++ 7.1 生成的程序大小与原始程序相同,因为 Ketchup 的 message map 几乎与 BEGIN_MSG_MAP
相同。 但 VC++ 7.1 无法内联消息处理程序,这与 BEGIN_MSG_MAP
不同。 这会不会是速度问题呢?
嗯,我无意模仿 BEGIN_MSG_MAP
的外观。 这不仅仅是语法糖,而是一种巧合,是由于与 ATL/WTL 命名一致性导致的。 这对我来说是一个惊人的发现。
顺便说一句,Ketchup 必须是第一个使用 Boost.Xpressive
进行实现的应用程序。
参考文献
历史
- 2005 年 5 月 23 日 - 版本 0.910 (初始发布)。
- 2005 年 5 月 27 日 - 版本 0.940。
- 2005 年 5 月 30 日 - 版本 0.950 (添加了
class_trace
和debugging_entry
)。 - 2005 年 6 月 12 日 - 版本 0.951 (移除了
debugging_entry
;添加了empty_entry
和debug_entry
)。 - 2005 年 7 月 20 日 - 版本 0.9992。