Message Only Window

Introduction

A Message Only Window is an invisible window, created with the sole purpose of picking up window messages. There's very little data associated with it and obviously no painting or similar operations. It's ideal for simple request-driven systems, where messages could be socket notifications, alerts from other processes, or triggers for inter-thread synchronization. There are many different scenarios where they can come in handy, one of which I'll write about in an article of its own later.

Creating such a window is nothing out of the ordinary. Register a class with a wndproc and instance handle, create a window granted the class name of the previous step, and the hWndParent set to HWND_MESSAGE: presto.

The scope of this article is not how to register classes or create windows—that's regarded as a fundamental (yet pretty manageable) requirement. The focus here will be making an efficient object oriented wrap of the Message Only Window concept, along with some best-practice key points and popular idioms. It will also utilize the Thunk32 library, the details of which were described in an earlier article: Thunking in Win32. Be sure to read up on that.

Getting Started

What you'd like to make, to begin with the end, is a set of classes that will allow you to do something along the lines of:

LRESULT onCreate(MessageOnlyWindow* wnd, UINT msg, WPARAM wParam,
                 LPARAM lParam)
{
   std::cout << "WM_CREATE" << std::endl;
   return 0;
}

int main()
{
   MessageOnlyWindow wnd;
   wnd.setMessageHandler(WM_CREATE, onCreate);
   wnd.create();
   wnd.enterMessageLoop();
   return 0;
}

Along with this, you'll want the completed mechanism to be thread safe, supporting one thread in the message loop, with others making calls to register or remove handlers. If multiple threads try to enter the message loop, only one should be able to do so, at any given time. To get there, you could use critical sections, mutexes, or an array of similar mechanisms. The mutex wrappers in boost, aptly named boost::mutex, wraps this up quite nicely—both with regard to the locking, and a proper cleanup when the objects fall out of scope.

Furthermore, to be able to easily set callbacks to be functions inside classes, as well as global or namespace scope, you'll be looking at boost::function and boost::bind.

All this baked together, you can come up with a first interface for the main class.

First Interface

class MessageOnlyWindow
{
public:
   typedef boost::function<LRESULT (MessageOnlyWindow*, UINT,
                                    WPARAM, LPARAM)> MESSAGEHANDLER;

   MessageOnlyWindow();
   ~MessageOnlyWindow();
   void create();
   void enterMessageLoop();
   void terminate();
   void setMessageHandler(UINT nMsg, MESSAGEHANDLER func);
   void removeMessageHandler(UINT nMsg);

   inline HWND getHWND() const
   { return m_hWnd; }
   inline LRESULT sendMessage(UINT nMsg, WPARAM wParam,
                              LPARAM lParam) const
   { return ::SendMessage(getHWND(), nMsg, wParam, lParam); }
   inline LRESULT postMessage(UINT nMsg, WPARAM wParam,
                              LPARAM lParam) const
   { return ::PostMessage(getHWND(), nMsg, wParam, lParam); }

private:
   typedef stdext::hash_map<UINT,
      MESSAGEHANDLER> MESSAGESIGNALMAP;
   typedef std::basic_string<TCHAR, std::char_traits<TCHAR>,
      std::allocator<TCHAR> > tstring;
   typedef std::basic_ostringstream<TCHAR, std::char_traits<TCHAR>,
      std::allocator<TCHAR> > tostringstream;

   HWND m_hWnd;
   BOOL m_bLoopRunning;
   BOOL m_bInitialized;
   HANDLE m_eventTerminated;
   boost::mutex m_mutexInitialize;
   boost::mutex m_mutexMessageLoop;
   boost::mutex m_mutexMessageMap;
   MESSAGESIGNALMAP m_mapMessageEvents;
   tstring m_szClassName;

   void cleanup();
   void registerDummyClass(WNDPROC pWndProc);
   void createWindow();
    LRESULT CALLBACK wndProc(HWND hWnd, UINT nMsg, WPARAM wParam,
                             LPARAM lParam);
};

This is not the completed class interface, but a grand place to start. Straight away, you probably spot some unfamiliar constructs, but for the sake of being pragmatic, I'll begin at the top.

Defining types is a good thing. I'm not one of those who desperately uses typedefs for any type combination in the spectre, but I do tend to use them when templates or function pointers are involved. The most obvious reason to use it is encapsulation. Not in the general sense, because the actual declaration is needed for the compiler to grasp anything, but in a way that hides complexity at points where it doesn't matter. Once you've comprehended that the MESSAGEHANDLER above is a boost::function, describing a functor with return type void, and a reference to the (still) undefined class WindowMessageInfo as sole parameter—there really is no use to keep repeating it. Repeating it in all functions will only clutter the interface, and make for a whole lot of unnecessary work should you want to change it later.

Moving along, let me quickly go through the functions.

  • create: Creates the message only window.
  • enterMessageLoop: Runs a message loop to dispatch incoming window messages. Will not return until terminate has been called, or WM_QUIT is received.
  • terminate: Ends a running message loop.
  • setMessageHandler: Associates a boost functor with the given window message code—overwrites any previously registered handler.
  • removeMessageHandler: Removes a previously registered handler.
  • getHWND: Returns a handle to the internal window.
  • sendMessage: Sends a message to the window, returns immediately.
  • postMessage: Posts a message to the window, and returns as soon as it has been processed.
  • cleanup: Reverses the process of create, and frees any temporaries.
  • registerDummyClass: Registers a window class, to be used by the MOW.
  • createWindow: Self-explaining helper of create.
  • wndProc: Receives messages, and possibly dispatches them to a handler function.

The parameters shipped to each of these functions should be fairly self-explanatory. The only unknown type should be "tstring", which essentially (as the typedef bear witness to) is a STL string whose internal storage unit will be the unicode friendly wchar_t if the _UNICODE preprocessor definition is specified, and a regular char otherwise. The history behind tostringstream is exactly the same, although it's never used as a parameter.

Functions that are guaranteed not to alter the class' instance members are tagged 'const', as they should be.

The instance member variables may seem unclear at this point. Why three mutexes? What's with m_eventTerminated? The usage will be illuminated in good time.

What this interface is clearly lacking, seeing as I mentioned usage of the Thunk32 library earlier on, is namely that—a thunk. You will also need another variable for the sake of creating unique window class names. Why am I not using one window class for all MOWs? Take a second to consider the consequences. When a window class is being registered, one has to supply a wndproc for it to use. You are free to associate another wndproc with a concrete window that implements this class, but there's no way of doing that prior to calling CreateWindow. Because of this, you would have to implement a single point of entry for the first (few) window messages—for example,through a singleton. Along with the word "singleton" comes a world of potential hurt, far outside the scope of this article. The more apparent of those woes would be to maintain thread safety. It is, however, by no means an impossible task—and in most situations, one common window class would be the way to go. However, the MOW mechanism described here is so lightweight, and so entirely simplistic, that the possible benefit of keeping a low window class count would be closely matched by the cost of extending the design and implementation.

On that note, I'll head over to the actual implementation. I will not be posting all of the source code here; that would be a whole lot more than necessary. Instead, I'll link to the completed library for download, at the end of the post.

Message Only Window

The Code

Before you get started with this, I'd like to bring forth one of the missing pieces of the interface puzzle.

indev::Thunk32<MessageOnlyWindow, LRESULT(HWND, UINT, WPARAM,
                                          LPARAM)> m_wndProcThunk

This is a private instance member, the type of which stems from the Thunk32 library. The declaration is somewhat similar to that of boost::function, as you may see. The first template parameter is the class in which the thunk will rely (if you're not familiar with thunks, I suggest you read my other article on those). The second template parameter is the signature of the wndProc function. Granted this declaration, you can take a look at the constructor of the MessageOnlyWindow class.

   MessageOnlyWindow::MessageOnlyWindow()
      : m_hWnd(NULL),
        m_bLoopRunning(FALSE),
        m_bInitialized(FALSE)
   {
      m_wndProcThunk.initializeThunk(this,
      // May throw std::exception
      &MessageOnlyWindowImpl::wndProc);
      m_eventTerminated = CreateEvent(NULL, TRUE, TRUE, NULL);
   }

The constructor initializes a few of the member variables within its member initialization list. For intrinsic types, such as the long that is BOOL, this is a matter of taste. I prefer to initialize all possible members in this way. For class members, on the other hand, they should always fed their first juice in the initialization list. Seeing as this is the only way to call the constructor of a non-pointer member that of class type, with parameters, you really have no other choice. For other types, such as strings, that allow you to both initialize them through constructors and assign to them through operators, there's somewhat of a difference. If you choose to set its value with the assignment operator, in the body of the constructor, you program will first construct it, and then assign to it. If you initialize it through the member initialization list, the first value the string gets will be what you want to initialize it to. To go with the assignment flavor will more likely than not cost you an extra couple of instructions, and you wouldn't want that, would you? For classes that aren't strings, the consequences may be far worse, so in either case—stick with the initialization list.

The thunk is initialized through its public function initializeThunk. The parameters are simply a pointer to the current class instance (this), and a pointer to the member function you wish to provide a trampoline for.

Next up, the create function. There's really not that much to this one, but it's reasonable to bring it up.

void MessageOnlyWindow::create()
{
   boost::mutex::scoped_lock lock(m_mutexInitialize);

   _ASSERT(m_bInitialized == FALSE);
   if(m_bInitialized)
      return;
   m_bInitialized = TRUE;

   try
   {
      registerDummyClass(reinterpret_cast<WNDPROC>
                         (m_wndProcThunk.getCallback()));
      createWindow();
   }
   catch(std::exception& e)
   {
      cleanup();
      throw;
   }
}

This is your first run-in with the mutex objects. The main purpose of the m_mutexInitialize mutex is to avoid race conditions where two threads attempt to initialize the MOW. I do hope you're familiar with mutexes, and if that's not the case, I might as well bring you up to speed on the problem: If two threads happen to call create at the "same" time, you'd experience what's called a race condition. That is, two threads are racing to complete the same operation. The exact timing of those operations, or rather how the CPU is being switched between the threads, will decide whether or not the application continues to run unaffected, or crash and burn. Some could expect the "if(flag) return; flag = true;" to be sufficient ... but it's really not. Imagine a scenario where one thread has just completed the instructions that make up the if, but is then swapped out in favor of another thread, before it's able to set the flag. That would leave you with two threads behind your if-barrier, both setting the flag and both free to register new window classes, create windows, and whatnot. The mutex will save you from that. Locking the mutex object m_mutexInitialize is guaranteed to be an atomic operation. A thread will either successfully lock the mutex, and continue running the code, or halt until whomever locked it has released it. In the case of boost's scoped_lock, this will last for the remainder of the function.

Also, take note of the doubly checked m_bInitialized. First an assertion, then a breaking if. The use of assertions typically symbolizes a situation that should never arise, and if it does, it's likely to be a critical design flaw of the application. Seeing as the _ASSERT macro is only defined for debug builds, I also apply the second test, which will effectively return you if the initialization has already been done. So in release build, the application won't fail or throw an exception, but rather fail silently—as everything is likely to keep running just fine. The flaw is still sufficiently severe to give the issue a hard fail if the application is being test run in a debug build.

The rest of the function is pretty straightforward. You register a window class, given the wndproc setup by the thunk, and then create a new window. If either of these operations fail, the MOW will undo whatever's been done, and further the exception back to the library client.

Okay, that's it for the initialization. I won't go much further into what registerDummyClass and createWindow do; the code will speak for itself. A final statement about the two will be brought up when I present the final interface, but for now I'll lay them to rest. The next part of the agenda is the actual message loop, enterMessageLoop.

void MessageOnlyWindow::enterMessageLoop()
{
   boost::mutex::scoped_lock lock(m_mutexMessageLoop);

   _ASSERT(m_bLoopRunning != TRUE);
   if(!m_bLoopRunning)
   {
      m_bLoopRunning = TRUE;
      // Signal that the message loop is running
      ResetEvent(m_eventTerminated);
   }
   else
   {
      throw std::exception("Message loop already running");
   }

   // Allow other threads to enter the function without blocking,
   // now that the m_bLoopRunning flag has been set
   lock.unlock();

   if(!m_bInitialized)
   {
      create();
   }

   // Keep track of which thread is inside the message loop
   m_dwIdOfThreadInMessageLoop = GetCurrentThreadId();

   MSG msg;
   while(GetMessage(&msg, getHWND(), 0, 0))
   {
      TranslateMessage(&msg);
      DispatchMessage(&msg);
      if(msg.message == WM_QUIT)
      {
         break;
      }
   }

   // No thread inside the message loop
   m_dwIdOfThreadInMessageLoop = 0;

   SetEvent(m_eventTerminated);    // Signal termination completed
   m_bLoopRunning = FALSE;
}

As with the previously explained function, there's a mutex lock up front. This is locking the same mutex object as before, but rather one intended solely for the message loop. When a lock has been successfully obtained, a check is made to see whether another thread is already inside this function. If that's not the case, the flag is set and an event is reset to signal that the loop is in effect. It then proceeds to unlock the mutex, allowing other threads to enter the function as they will. Effectively, only one thread will be running between the initial lock and unlock at any one time, while a second thread is free to actually pump the messages. It would arguably be a design flaw if two threads attempted to enter this function, as the assert illustrates, but that error should still not make the application deadlock in the release build. Compared to the create function, enterMessageLoop may run for a very, very long time, which would mean that another thread attempting to call it would lock for an indefinite amount of time, or even deadlock the application completely. In the case of the implementation above, one thread will be allowed in the message loop, and another may try to enter—only to have an exception thrown at it instead, which the library user is free to catch, log, and deal with. Attempting to cover up all possible problems, both with verbose asserts and "soft failures," is part of the discipline known as Defensive programming.

The last thing worth taking a notice of in this function is the m_dwIdOfThreadInMessageLoop variable. While a thread resides within the loop, this will hold its id. This info can used in other functions, such as terminate, to see if the call of a library function is likely to come from a message handler (which has been dispatched through the message loop). The motivation for doing this check is to avoid deadlocks. Imagine a terminate function that issues a WM_QUIT and bluntly waits for m_eventTerminated to be signaled, indicating that you've successfully shut down. If that terminate is called from a message handler, the thread would in effect be waiting for itself to perform an action. Obviously, that will never happen, and you'll have a deadlock on your hands.

Message Only Window

Intervention

Thus far, we've got an incomplete interface, some thread safe code and a message pump. Things are really looking grand. That being said, I'd like to mold your mind a little before I let go of the completed class interface. The keyword is once again encapsulation. Generally, the idea behind encapsulation is to reveal nothing more about inner workings than absolutely necessary. First and foremost, that's done through pragmatism. Provide clear and concise interfaces, and avoiding to clutter them with unnecesary tasks, options and access.

One specific piece of clutter one would generally want to stay away from, is access to internal handles. I bring that up because of the getHWND function provided by the MOW class. Obviously that qualifies as an internal handle, and we're given full access to it. In this case, dealing with it would be horribly impractical. The only half suitable solution would be to provide all HWND related operations through the MOW's public interface, but that would render the class completely useless. More often than not, message only windows are passed by their handle to function sunch as those in the asynchronous parts of the WinSock library, and that would obviously be impossible without access to the actual handle.

Member variables is another thing one really should protect. A rule of thumb is to always have member variables declared private. Some will even suggest that this should be done for classes meant for inheritance, and only provide access through protected getter and setter functions. In the MOW case, this really isn't a problem. The class is not meant for inheritance (hence the non-virtual destructor), and there's no other need to expose any variables. The protection, however, is an interesting point to bring up. In a real world case, where a class such as this is to be provided by you to a bunch of users, you would ship a header and a static library (.lib). Even before I've provided the complete interface, just looking at the incomplete one further up will make it pretty clear that the interface itself reveals more than necessary about how the class works. Having the private functions and variables for all to gaze upon, has a tendency of telling a bit too much. A user could e.g. jump to the conclusion that the class is completely thread safe by seeing a couple of mutex objects. In this case this wouldn't be too harmfull, as it shoud actually be thread safe, but it does impose some restrictions to our future of the library. If we decided not to mention the thread safety in the documentation, as we either not put the mutex objects to use, or had plans of removing them in the future, we couldn't just go ahead and do that. The user may already have incorporated the library deep in his software, complete with assumptions to both thread safety and other issues, drawn from the private interface, thus ending up with a heapload of weird errors, debugging, support and generally unhappy campers on all sides. The solution to this is the PIMPL idiom (Pointer to IMPLementation).

The PIMPL

The PIMPL idiom simply states that the only private member of a class interface should be that to another class instance which provides the implementation. The implementation interface is of course not shipped with a library, as the compiler has no need for it. All the compiler needs is being told that the class exists, through a pre-declaration, and the rest is taken care of by the compiled translation unit -- in other words a .cpp which is compiled into the static library.

The PIMPL isn't just good news for encapsulation (more specifically; information hiding), but in many cases also compilation times. When pimpls are used, changes to implementation, or the implementation's interface, is unlikely to cause rebuilds propagating throughout the source.

The impact of the pimpl in the case of the MOW, really isn't that grand. Starting with the cost, we will face a couple of more instructions per call to the public interface, but that's really nothing to worry about. Furthermore, we'd have to provide two, virtually identical, interfaces: one internal and one external. The class which utilizes the pimpl will merely be a proxy to the implementation, so all public functions will have to call to the proper ones.

Pimpled MessageOnlyWindow interface

class MessageOnlyWindow
{
public:
    typedef boost::function<LRESULT (MessageOnlyWindow*, UINT, WPARAM, LPARAM)> MESSAGEHANDLER;

    MessageOnlyWindow();
    void create();
    void enterMessageLoop();
    void terminate();
    void setMessageHandler(UINT nMsg, MESSAGEHANDLER func);
    void removeMessageHandler(UINT nMsg);
    HWND getHWND() const;
    LRESULT sendMessage(UINT nMsg, WPARAM wParam, LPARAM lParam) const;
    LRESULT postMessage(UINT nMsg, WPARAM wParam, LPARAM lParam) const;

private:
    std::auto_ptr<class MessageOnlyWindowImpl> m_pImpl;
};

As you can see, this looks pretty much the same as the first interface provided. The only change is the private parts, now consisting of nothing but a smartpointer. The MessageOnlyWindowImpl is the real class, and that's simply predeclared using the "class MessageOnlyWindowImpl" syntax seen in the smartpointer declaration seen above.

class MessageOnlyWindowImpl
{
public:
    typedef boost::function<LRESULT (class MessageOnlyWindow*, UINT, WPARAM, LPARAM)> MESSAGEHANDLER;

    MessageOnlyWindowImpl();
    ~MessageOnlyWindowImpl();
    void create();
    void enterMessageLoop();
    void terminate();
    void setMessageHandler(UINT nMsg, MESSAGEHANDLER func);
    void removeMessageHandler(UINT nMsg);

    inline void setBaseMessageOnlyWindowPtr(class MessageOnlyWindow* pBaseMOW)
    { m_pBaseMOW = pBaseMOW; }
    inline HWND getHWND() const
    { return m_hWnd; } 
    LRESULT sendMessage(UINT nMsg, WPARAM wParam, LPARAM lParam) const
    { return ::SendMessage(getHWND(), nMsg, wParam, lParam); }
    LRESULT postMessage(UINT nMsg, WPARAM wParam, LPARAM lParam) const
    { return ::PostMessage(getHWND(), nMsg, wParam, lParam); }

private:
    typedef stdext::hash_map<UINT, MESSAGEHANDLER> MESSAGESIGNALMAP;
    typedef std::basic_string<TCHAR, std::char_traits<TCHAR>, std::allocator<TCHAR> > tstring;
    typedef std::basic_ostringstream<TCHAR, std::char_traits<TCHAR>, std::allocator<TCHAR> > tostringstream;

    class MessageOnlyWindow* m_pBaseMOW;
    HWND m_hWnd;
    BOOL m_bLoopRunning;
    BOOL m_bInitialized;
    HANDLE m_eventTerminated;
    boost::mutex m_mutexInitialize;
    boost::mutex m_mutexMessageLoop;
    boost::mutex m_mutexMessageMap;
    MESSAGESIGNALMAP m_mapMessageEvents;
    tstring m_szClassName;
    DWORD m_dwIdOfThreadInMessageLoop;

    indev::Thunk32<MessageOnlyWindowImpl, LRESULT(HWND, UINT, WPARAM, LPARAM)> m_wndProcThunk;
    
    void cleanup();
    void registerDummyClass(WNDPROC pWndProc);
    void createWindow();
    LRESULT CALLBACK wndProc(HWND hWnd, UINT nMsg, WPARAM wParam, LPARAM lParam);

    volatile static long ms_nClassInstances;
    static tstring generateUniqueClassName();
};

Now this is the real McCoy. Straight away, I bet you agree that the previous interface is a lot easier to accustom oneself to than this one -- and thus, the first purpose of the pimpl has been reached.

There are some additions to this interface, compared to the first one, but none of them are particularly complex.

  • The static variable ms_nClassInstances. It is there to serve as an application wide counter of registered MOW classes (see further up for the discussions on why I chose to register unique classes). It's declared volatile and incremented with the InterlockedIncrement function of the Platform SDK, which is guaranteed to return a unique number, even when accessed by multiple threads.
  • A pointer to the "base" MOW class is kept as m_pBaseMOW, and assigned through the setBaseMessageOnlyWindowPtr function. This is needed for the window procedure to dispatch calls to message handlers with the MOW as the first parameter.

The code v2

The implementation of MessageOnlyWindowImpl is basically unchanged across the swap of names. The new MessageOnlyWindow is also a trivial piece, as this class now acts solely as a proxy to the real implementation. Showing two functions will pretty much show them all:

MessageOnlyWindow::MessageOnlyWindow()
    : m_pImpl(new MessageOnlyWindowImpl())
{
    m_pImpl->setBaseMessageOnlyWindowPtr(this);
}

void MessageOnlyWindow::create()
{
    m_pImpl->create();
}

Obviously, as mentioned earlier, the pimpl will cost an extra indirection. For software where this is likely to have a grand impact, you may wish to leave it out. Generally, the difference will not be noticeable at all. Run a test application through your favorite profiler to confirm this.

That's really all that needs to be said.

Recap

What we've been doing, in case you missed it, is creating a generalized class for message only window. The class demonstrates how to use the Thunk32 library (http://www.codeguru.com/cpp/w-p/win32/tutorials/article.php/c12667/) to create pointers to non-static member functions, the purpose of the PIMPL, and some OO best practices. You should take the time to read through the source of the attached project, as that may clear up on some of the questions you are currently stuck with. The MOW principle is a fairly simple matter, and so it the final usage of the class. Can the use approach depicted in the beginning be used with the final product? Indeed it can. Since we're utilizing boost functors for message callbacks, we can even look to boost::bind more flexibility, including (but not limited to):

  • Parameter binding
  • Parameter reordering
  • boost::lamda lazy transformations
  • Bindings to non-static member functions

So there it is. And that really ought to be it for now. If you've got any questions, be sure to ask!



About the Author

Einar Otto Stangvik

My name is Einar Otto Stangvik, and I'm a programmer based in Oslo, Norway. I mainly develop applications and software architectures targetting C++ on the Windows platform, but I have also got experience doing the same on Unix and Linux. Lately, I've looked to C# for some projects, but native C++ is still my main focus. See my site, http://www.indev.no, for more information. My code blog can be found at http://einaros.blogspot.com.

Downloads

Comments

  • There are no comments yet. Be the first to comment!

Leave a Comment
  • Your email address will not be published. All fields are required.

Top White Papers and Webcasts

  • On-demand Event Event Date: September 10, 2014 Modern mobile applications connect systems-of-engagement (mobile apps) with systems-of-record (traditional IT) to deliver new and innovative business value. But the lifecycle for development of mobile apps is also new and different. Emerging trends in mobile development call for faster delivery of incremental features, coupled with feedback from the users of the app "in the wild." This loop of continuous delivery and continuous feedback is how the best mobile …

  • Packaged application development teams frequently operate with limited testing environments due to time and labor constraints. By virtualizing the entire application stack, packaged application development teams can deliver business results faster, at higher quality, and with lower risk.

Most Popular Programming Stories

More for Developers

Latest Developer Headlines

RSS Feeds