In the accompanying article, Enabling and disabling commands in an ObjectWindows application we show you how to enable and disable menu commands with the ObjectWindows Library (OWL) version 2.0. To enable or disable commands this way, you have to provide a command-enabler function that accepts a reference to a TCommandEnabler object as its only parameter.
If you place your command-enabler function in a message-response
table, OWL will call this function when it needs to know the enabled/disabled
status of the function's corresponding command. When OWL
calls your command-enabler function, OWL passes the address of
an object derived from the TCommandEnabler class that
will perform the actual enabling or disabling of the command control
for you.
OWL derives two classes from the TCommandEnabler class
for you: the TMenuItemEnabler class and the TButtonGadgetEnabler
class. Both classes overload the Enable(), SetText(),
and SetCheck() member functions to set the appropriate
visual state for the corresponding TMenu or TButtonGadget
object. Since the behavior of these two classes is the same in
all other ways, we'll look only at the TMenuItemEnabler
class.
When an OWL application receives the message EV_WM_INITMENUPOPUP from Windows, the application calls the TFrameWindow or TFrameWindow-derived class's EvInitMenuPopup() member function to handle the message. In turn, this function calls the TFrameWindow class's EvCommandEnable() function to begin searching for corresponding command-enabler functions for each command in the menu. (Page 420 of the ObjectWindows 2.0 Reference Guide contains a diagram that illustrates how the TWindow class's DefaultProcessing() function processes messages. The TFrameWindow class inherits this public member function.)
If you've provided an appropriate command-enabler function
for a given command ID, the EvCommandEnable() function
will eventually locate and call your command-enabler function
and pass it the current TMenuItemEnabler object. When
your command-enabler function calls the Enable() member
function of the TMenuItemEnabler object with TRUE or
FALSE, the TMenuItemEnabler object sets the menu item's
MF_GRAYED flag to the appropriate value by using the standard
Windows function EnableMenuItem().
You don't have to put all your command-enabler functions in your application class. You can put command-enabler functions for individual commands in separate window classes. This is particularly useful when you implement certain commands only when a specific type of client window is open.
When OWL is about to display a command object, the EvCommandEnable() function searches the classes of the objects in the current view hierarchy, or chain, beginning with the command object's parent window. The EvCommandEnable() function continues searching the class of each object in the chain until it finds a command-enabler function or until it reaches the end of the chain (the application object).
For example, when an OWL application is about to display a menu in a client window, OWL first searches in the client window object's class for command-enabler functions for the menu commands. If there isn't a corresponding handler for a command in the client window object's class, OWL will search the class of the frame window object and then finally the class of the application object.
If OWL finds a command-enabler function for a given command, it stops searching the command-enabler chain. However, if OWL doesn't find an appropriate command-enabler by the time it finishes searching the application object's class, it will disable the corresponding command automatically.
This means that OWL will always disable your new menu commands
unless you provide a command-enabler function for them.
This explains why you can't use the EnableMenuItem()
API function to enable a menu item directly. As soon as the function
begins displaying the menu, OWL creates a TMenuItemEnabler
object whose default behavior disables menu commands.
It may seem strange to create command-enabler functions that use
a TCommandEnabler object you don't need to create
yourself. However, by doing so, you allow OWL to take the responsibility
for calling your command-enabler functions when necessary.