message_parliament etc. Userís Guide

This explains the message routing system comprising the classes message_parliament, minister, and commission.

Related Documents

Contents

Overview

This system provides for window message routing with a fine level of granularity and refactorization. The class message_parliament is a mix-in that supplies an implementation for handle_message that dispatches messages to components that encapsulate small units of functionality.

Besides enabling reuse of implementation of individual features, the routing system is built up at run time so features can be added or changed without altering the base classes or other code in the implementation of the whole window. Furthermore, enabling and changing such features at run-time is a direct way to implement state in the system: for example, when the mouse button is pressed, a feature for reacting to the mouse movement can be added in, and when the button is released that feature is removed, thus implementing a drag operation.

Relationship

The individual units of functionality are objects derived from the minister class. The message_parliament is a collection of commission objects.

diagram

The message_parliament class implements a message handler that works by traversing the array of commissions to see which can handle that message. It is designed to work with the message_tap class, in that this class provides an implementation and that class calls it.

In operation,

One minister can serve more than one message_parliament. One minister can have multiple occurances (commissions) in the same parliament.

Threading Issues

The Win32 messaging system goes to great lengths to ensure that a message is always handled on the correct thread for that window. This means that you can assume that message_parliament::handle_message and minister::administer_message is only called by the correct thread, and that calls are serialized or nested. In cases where a WndProc sends a synchronous message to another window, Win32 documents specific threading behavior between the threads assigned to the calling and called WndProcs. These functions are triggered directly by the WndProc, so youíll see the same threading behavior.

The calls to message_parliament manipulation functions such as add, find, and remove can be called by any thread at any time. Simultainious calls to functions that manipulate the commission list are automatically serialized.

However, the traversal code (as executed by handle_message) is asynchronous from all that. If other threads are changing the commission list at the same time that the window thread is processing a message, the message processing will see a static image of the commission list as it existed when that messageís work was started. The traversal loop will not see any changes that are being made while it is being traversed. However, the object passed as a parameter to administer_message will see the up-to-date state and can make its own calls to add and remove.

As described in the next section, the minister is not (necessarily) owned by the message_parliament. So, it is possible for a minister to be destroyed after all its commissions are removed from all message_parliament objects, but a thread traversing the commission list at the time will not realize that this commission was removed, as it sees the state as it was when that message was received. The baro smart pointer technology will reliably detect a stale pointer, and the traversal will silently skip that minister.

Housekeeping Issues

The message_parliament implements handle_message, so it needs to live as long as anything pointing to it exists and can send messages. In normal use, the message_tap class takes care of this so you donít need to worry about it. The message_parliament is managed using smart pointers, and will not be destructed until it is unhooked from the primitive WndProc.

The ministers are held using non-owned smart pointers (classics::baro), to prevent circular ownership. If need be, a baro pointer can have ownership. If left unowned, there is a possibility that a minister can be destroyed on one thread while the commissions are being traversed by another. This is handled robustly and silently. If left dangling (as opposed to just happening once to do the asynchronous nature), it might be smart enough to inform you of a programming error, but it will never cause problems.

Both message_parliament and minister objects are meant to be used with smart pointers, and must be created using new. The commission records, on the other hand, are manipulated by value. You can create a temporary commission and pass it to message_parliament::add, for example.

How to Use

  1. Use message_parliament as a base class in your window, to provide the implementation of the handle_message function. Note that class eagduru does this.
  2. Implement classes derived from minister as a window mix-in that provides handling for a small number of windows messages forming a single feature, via the administer_message function. Or, choose from the set of such classes that have already been written.
  3. Write your window class to mix-in all the desired ministers, as well as the message_parliament and other classes required.
  4. Populate the objectís parliament with commissions, which point to the ministers that will be doing the work of governing the window.
  5. You may add and remove commissions from the collection at run-time to change the behavior of the window.

For a class whose behavior is all compiled together, making the ministers mix-ins to the concrete window class is the easiest thing to do. However, for more dynamic behavior such as when the number of ministers can increase without pre-determined limit, it becomes necessary to dynamically allocate them separate from the window itself.

The minister may be any object, unrelated to the window if you like, as long as it derives from the minister base class. The minister objects can simply point back to the window they control, or be part of some other architecture, as desired.

Example: First Parliament

This is a working program that uses the message_parliament and its attendant classes in a simple manner. It is stripped-down, in that it doesnít do anything useful other than illustrate these calls, but it is not actually the simplest possible since it illustrates several variations.

The code is found in first_parliament.cxx in the tomahawk\Samples\First Parliament directory. The project file is included in the all workspace and is found in the compile.vc71 (or higher) directory.

You may want to compare this code to that of message_tap_demo.cxx, which does not use the parliament, but processes messages directly in the implementation of handle_message.

Class par1

The class par1, short for parliament one, has several base classes:

class par1 :
	public message_tap,
	public message_parliament,
	public minister
	{
	…

Note that class eagduru derives from these, and more. But these are the minimal to do this.

The two base classes message_tap and message_parliament work together. The message_parliament (which we are illustrating in this guide) takes messages from one stream and delivers them to various ministers. The message_tap obtains that central stream from the Win32 primitive dispatching system. Simply deriving from both of them will merge the two together into a seamless whole, so that Win32 messages dispatched to the attached HWND will be routed to the proper minister. See the description for message_parliament::handle_message.

So why are they two different classes? They are responsible for different things. You could, for example, derive from either or both classes to modify them, and then use both derived classes. With a monolithic design, you cannot derive from just one part thatís burried under the surface somewhere. With Tomahawk, each component can be modified or replaced independantly.

Now the third base class of par1 is minister. The same object that is the parliament is a minister as well. This means that the implementation of administer_message will be a virtual override in this same class. That is certainly allowed, and it often makes sence to have the objectís unique handling implemented here, in addition to other ministers that are used.

void par1::add_minister()
 {
 using namespace ratwin::WM_constants;
 tomahawk::message_range range;
 range << WM_MOUSEMOVE << WM_SIZE;
 message_parliament::add (this, range);
 }

Here is the code to add the minister (itself) to the parliament (itself), neatly put into its own function that is called at construction time.

The using directive makes it easy to refer to the message names. The second line defines a message_range object, and the third line stuffs it with all the messages of interest. Finally, the fourth line calls add. The function name is qualified just to be clear. Since this came from a base class, there may be functions named add in this class that are totally unrelated, or functions named add in other base classes. There may indeed be a conflict or hiding issue in a real situation. Using the qualified name of the function is no harder than if the function were given a more elaborate name in the first place, such as add_minister_to_parliament.

The call to add takes a pointer to the minister (itself) and the range object created beforehand. We donít deal directly with a commission object, but one is created by add. Its pointer to the minister is implemented using a baro, or non-owning smart pointer. So, there is no problem with this object (in its role as parliament) having a smart pointer to itself (in its role as minister), since the reference count is not incremented.

Now take a look at the function we worked so hard to get called:

par1::administer_result_t par1::administer_message (sMSG& msg, const traversal_state&)
 {
 using namespace ratwin::WM_constants;
 switch (msg.message) {
    case WM_MOUSEMOVE:
       process_MouseMove (MSG_cast<WM_MOUSEMOVE_msg>(msg));
       return Handled;
    case WM_SIZE:
       process_Size (MSG_cast<WM_SIZE_msg>(msg));
       return Handled;
    }
 return NeverHandles;
 }

It only has to handle the messages that this minister is signed up for, and does not itself need to do anything to allow other pieces of code to contribute. Here, another member function is written for each of the two messages, with MSG_cast used to prepare the parameters for each one. Each of the two cases returns Handled, to inform the parliament that this was taken care of.

If the message is not one of those that this minister can handle, it returns NeverHandles. This function should always do this if called for a message number that is not what it signed up for. It should expect such unnecessary calls to actually occur, and return quickly.

Of the parameters being passed to administer_message, this simple implementation only cares about the first one, the msg. The information in the state could be used if the code needed to determine the context of things or interact with the parliament that called it. But if you donít need them, donít worry about it.

class ExtMin — an external minister

Some other messages are handled by a different class. That is, it is not implemented as part of the par1 class, but is an independant object. This class is simpler than the first, because it is only a minister and is not all those other things too.

class ExtMin : public tomahawk::minister {
   classics::baro<par1> parent;
public:
   ExtMin (par1* parent);
   administer_result_t administer_message (sMSG& msg, const traversal_state&);
   };

The class ExtMin is small, deriving from only one parent, containing only the constructor and and administer_message functions, and private data.

The main window implementation object can create and add this minister to its parliament at any time. It may specifically be added and removed on the fly in response to some other event. But here we are modeling the use of a pre-made minister class simply for code reuse. In the example code, it doesnít really matter where this is done, and obvious places are either in par1ís constructor or par1::on_attach. By convention, pre-made ministers for code reuse are added during on_attach, since that is done later and the minister can immediatly know that the HWND exists. In fact, another reason for adding the minister here instead of at construction time (of par1) is because it may be inconvenient to do the work before the HWND is ready.

void par1::add_external_minister()
 {
 new ExtMin (this);
 }

ExtMin::ExtMin (par1* parent) :parent(parent) { using namespace ratwin::WM_constants; tomahawk::message_range range; range << WM_LBUTTONDOWN; message_parliament::locked_commission commish (parent->message_parliament::add (this, range)); commish->appointed_minister.own(true); }

At whatever point itís done, par1 simply calls new ExtMin (this); and does nothing else. Clearly this means that the constructor itself takes care of adding the minister to the parliament (which it gets via the parameter), but it may seem curious that the pointer returned by the new expression is not saved anywhere. The minister, once added to the parliament, does not need to be remembered specifically by par1 for any reason.

The constructor code remembers parent for future reference, as the object it will manipulate when messages are handled. The private data member is a baro, or unowned smart pointer, so it does not have to worry about the lifetime of the object, but doesnít cause circular ownership either.

The parent is also used in the call to message_parliament::add. The par1 is controlled by direct knowledge of its member functions, since ExtMin was written for the purpose; and also knows that par1 is derived from message_parliament. However, for general-purpose reusable minister objects (e.g. see click_minister), the object to be manipulated by the messages and the parliament to add itself to may be different.

As mentioned, the constructor calls add. But, it also notes the return value from that function in the local variable commish. This is for use by the next line, commish->appointed_minister.own(true);. The variable commish lets the code further modify the commission from what was set up by this simple form of add. Specifically, it tells the commission to own the pointer, rather than leave the default state of unowned. The presence of this pointer in the parliament will be what keeps this object alive, since (as noted earlier) it is not being remembered by the par1 object. The option to use owned, rather than unowned pointers, is handy for the case of ministers as external objects1.

Finally, the implementation of administer_message:

ExtMin::administer_result_t ExtMin::administer_message (sMSG& msg, const traversal_state&)
 {
 using namespace ratwin::WM_constants;
 switch (msg.message) {
    case WM_LBUTTONDOWN: {
       classics::handle<par1> p (parent);
       p->count ( 1+p->count() );
       } break;
    default:  return NeverHandles;
    }
 return Handled;
 }

This function detects the desired message, and for demonstration purposes simply increments a counter in the object it is servicing. It defines p instead of using parent directly because thatís the way the baro class is used.

message_range class

This is linked to from the class summary. Make sure a section with this id exists in this file.

Footnotes

Owned pointers are handy for ministers as external objects:

In fact, this is the use-case that demanded that the baro class have this feature.