65.9K
CodeProject is changing. Read more.
Home

Good bye, BEGIN_MSG_MAP!

starIconstarIconstarIcon
emptyStarIcon
starIcon
emptyStarIcon

3.46/5 (17 votes)

May 28, 2005

2 min read

viewsIcon

71694

downloadIcon

384

A replacement for BEGIN_MSG_MAP macros, using the Boost.MPL library.

Preface

Four yeas ago, I made a program. Everything WTL originally had was useless except Win32 thin wrappers. As CUpdateUI was the one of them, I made the replacement by macros. Later, I read the book, C++ Template Metaprogramming, and I was inspired by the sample code, the finite state machine. That could remove the macros and the result was named ketchup, intended to replace BEGIN_MSG_MAP of ATL/WTL.

In time, the experience of making biscuit gave me the way of avoiding compile-time crashes. Now that ketchup is the type-safe synonym of BEGIN_MSG_MAP to help WTL catch up the modern programming.

Introduction

Ketchup is a message map generator implemented using class templates. The templates allow us to write type-safe BEGIN_MSG_MAP.

A simple BEGIN_MSG_MAP macro snippet:

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()

is approximated using Ketchup's facilities as seen in this code snippet:

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;

Requirements

Microsoft Visual C++ .NET version 7.1, WTL 7.5 and Boost C++ libraries (no build required). I did test the demo in Visual C++ .NET standard edition with Visual C++ toolkit 2003. Ketchup itself is a header-only template library.

Quick Start

  1. Include a header and derive from 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>
    {
  2. Define message handlers:
    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());
        // ...
      }
      // ...
  3. Let CMainFrame a message map:
    public:
      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;
  4. Finally, override CMessageMap::ProcessWindowMessage as BEGIN_MSG_MAP insidiously does, using process_window_message provided by ketchup::message_processor<CMainFrame>:
      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);
      }
    };

Bear in mind that declarations of message handlers should be placed before the entry and C++ Standard doesn't allow you to abbreviate the syntax of member function pointers.

Points of interest

The last point is the performance. The program size seems not to be a problem. VC++ 7.1 generates the same size program as the original one, because Ketchup's message map is almost same as BEGIN_MSG_MAP. But VC++ 7.1 can't inline message handlers, unlike BEGIN_MSG_MAP. Could this be a problem of the speed?

Well, I did not intend to emulate the appearance of BEGIN_MSG_MAP. It is not just a syntax sugar but the coincidence as a result of naming consistency with ATL/WTL. It was an amazing discovery for me.

By the way, Ketchup must be the first application using Boost.Xpressive for the implementation.

References

History

  • 23rd May, 2005 - version 0.910 (Initial release).
  • 27th May, 2005 - version 0.940.
  • 30th May, 2005 - version 0.950 (class_trace and debugging_entry added).
  • 12th Jun, 2005 - version 0.951 (debugging_entry removed; empty_entry and debug_entry added).
  • 20th Jul, 2005 - version 0.9992.