Even the most committed C++ developer can get frustrated with the logistics of keeping C++ header and source files synchronized, particularly when a large refactoring exercise needs to be completed. On top of the tedious nature of changing method signatures, achieving the correct syntax for handling MFC commands and Windows messages is a task that can be better achieved by an IDE tool rather than a developer toiling away in a text editor. Classic versions of Visual C++ (where 'classic' is defined as Visual C++ versions that existed as an independent IDE rather than integrated in Microsoft Visual Studio had an elegant tool that addressed this problem, and the long-promised return of the Class Wizard is achieved in Visual C++ 2010.
Highlighting its specific-Visual C++ nature, the Class Wizard is launched from the Project IDE menu rather than the view menu where many of the other code navigation windows are launched. The Class Wizard is divided into five tabs, with the first two specifically designed to make working with MFC commands and Windows messages simpler. All tabs share a common header control that allows the project and class that the Class Wizard is displaying to be selected, with the Base Class, Resource name, header file and implementation file of the selected class all displayed.
Figure 1. Visual C++ Class Wizard - MFC Command Tab
The MFC Command Tab, shown in Figure 1, allows for the easy addition, deletion and code management of handlers for MFC Commands. For those with a scratchy memory on the differences between MFC commands and Windows messages, it's worth a brief discussion on what each represents. MFC commands derive from the special Windows message
WM_COMMAND which is used to notify the application that a command has been executed by the user, such as when a menu item has been selected. MFC uses a macro-based message map to convert these commands to specific functions, and any MFC class that is derived from CWnd can have its own message map. Commands are high-level, and map multiple physical actions like Ctrl-C and Edit | Copy to the same command. On top of the main
ON_COMMAND macro, MFC also supports a
ON_UPDATE_COMMAND_UI macro which is used to query the application about the display state of a menu item, such as whether it should be disabled or appear.
The message map for the command handlers shown in Figure 1 is:
BEGIN_MESSAGE_MAP(CClassView, CDockablePane) ON_COMMAND(ID_CLASS_ADD_MEMBER_FUNCTION, OnClassAddMemberFunction) ON_COMMAND(ID_CLASS_ADD_MEMBER_VARIABLE, OnClassAddMemberVariable) ON_COMMAND(ID_CLASS_DEFINITION, OnClassDefinition) ON_COMMAND(ID_CLASS_PROPERTIES, OnClassProperties) ON_COMMAND(ID_NEW_FOLDER, OnNewFolder) ON_COMMAND_RANGE(ID_SORTING_GROUPBYTYPE, ID_SORTING_SORTBYACCESS, OnSort) ON_UPDATE_COMMAND_UI_RANGE(ID_SORTING_GROUPBYTYPE, ID_SORTING_SORTBYACCESS, OnUpdateSort) END_MESSAGE_MAP()
By using the Class Wizard, these message map entries and the associated class methods can be located, added to and deleted, saving a great deal of time manually adding the required entries and debugging commands that are mysteriously left unfired.
In contrast to the narrow range of MFC commands, Windows messages encompass a much wider range of event notifications, such as window creation and destruction, events related to power management in Windows and changes of screen resolution and orientation. Figure 2 shows the Message tab of the Class Wizard.
Figure 2. Class Wizard - Message Tab
In addition to the features that are present on the MFC command tab, the Message tab allows custom messages to be handled via the pop-up dialog shown in Figure 3.
Figure 3. Handling Custom Message
For the message shown in the dialog, the definition of the custom message in the form #define WM_MY_MESSAGE WM_USER + 0 must be available to the source file containing the message handler. Windows message handlers are included in the message map using either the
#define WM_MY_MESSAGE WM_USER + 0 static UINT WM_MY_CUSTOM_REGISTERED_MESSAGE = RegisterWindowMessage(_T("MY_CUSTOM_MESSAGE")); BEGIN_MESSAGE_MAP(CAboutDlg, CDialogEx) ON_MESSAGE(WM_GESTURE, &CAboutDlg::OnGesture) ON_WM_ACTIVATE() ON_MESSAGE(WM_MY_MESSAGE, &CAboutDlg::OnMyMessage) ON_REGISTERED_MESSAGE(WM_MY_CUSTOM_REGISTERED_MESSAGE, &CAboutDlg::OnMyCustomRegisteredMessage) END_MESSAGE_MAP()
MFC provides pre-defined message handlers like
ON_WM_ACTIVATE that are mapped to pre-defined functions like
CWnd::OnActivate. For standard Windows messages that are not present in the Class Wizard listbox, the Add Custom Message dialog can be used to map a member function. In the message map above, the
WM_GESTURE message, which is used to provide touch-based gesture support in Windows 7 and above, has been mapped.
In contrast to the first two tabs of the Class Wizard that are specifically designed to provide support for MFC Windows applications, the last three tabs of the Class Wizard that deal with Virtual Functions, Member Variables and Methods can be effectively used with any type of C++ application. The Virtual Function tab, shown in Figure 4, is extremely useful when dealing with classes derived from a deep and rich framework like MFC. For classes derived from
CDoc, there are literally dozens of virtual functions in base classes that can be derived from in order to customize certain behavior, and locating these function and providing the appropriate method signature can be a tedious exercise of copy-and-pasting from documentation or header files. The Class Wizard greatly simplifies this task.
Figure 4. Class Wizard - Virtual Functions
The final two tabs which display Member Variables and Virtual Functions, which are shown in Figures 5 and 6 respectively, focus more on managing the class selected in the drop-down in the Class Wizard header. The Member Variable tab allows either a standard member variable to be added via the Add Custom selection, or for the addition of a variable that maps to a MFC controls and hooks into the DDX data exchange between control and variables. With the Methods tab, methods can be added and deleted from a class, and support exists to navigate to either the declaration or definition of any existing method.
Figure 5. Class Wizard - Member Variables
Figure 6. Class Wizard - Methods
The integration of Visual C++ inside the main Visual Studio IDE and the focus on managed development that accompanied the .NET release caused some regression in the features available to a C++ developer. With Visual C++ 2008 and 2010, this regression has been thoroughly addressed, and Visual C++ 2010 is a product that can comfortably compete with Visual C++ 6 on an age-adjusted scale. The Class Wizard was an important tool for many C++ developers, especially for the production of MFC GUI applications where a lot of the manual work of command and message mapping could be easily managed, and the return of this tool will give many long-suffering Visual C++ developers yet another reason to consider retiring the 'suffering' tag and enjoy Visual C++ development again.