WM_COMMAND messages receive special handling in MFC. Instead of being sent only to windows, they are routed in a predetermined way among the objects¾ called "command targets" ¾ in the running application. Besides windows and views, other objects get a chance to handle commands, including documents. The idea is that a command ought to be handled by the object with the most relevant information about the command.
Each class derived ultimately from class CCmdTarget (including CWnd, CView, CDocument, and others) has an OnCmdMsg function. OnCmdMsg checks the object's message map and may also route the command to other command-target objects. (Message maps are discussed later in "Using the MFC Message Map.")
Figure 8 illustrates MFC command routing in a simplified way.
For this conversion process, you simply move all WM_COMMAND code into an override of CView::OnCmdMsg.
For SHOWDIB, override OnCmdMsg in the view class and move all code now in the MenuCommand function (SHOWDIB.CPP) into OnCmdMsg. A much-abbreviated version of the view's OnCmdMsg handler looks like this:
BOOL CShowDibView::OnCmdMsg(UINT nID, int nCode, void* pExtra,
AFX_CMDHANDLERINFO* pHandlerInfo)
{
// for converting hWnd parameters to use m_hWnd member variable
HWND hWnd = GetSafeHwnd();
// The following if statement screens out MFC codes that
// you don't want to handle here
if (nCode != 0) // ignore new MFC requests
return FALSE;
// old WM_COMMAND code (moved from ShowDib's MenuCommand function
// for C++ conversion)
BITMAPINFOHEADER bi;
HDC hDC;
HANDLE h;
HBITMAP hbm;
HPALETTE hpal;
WORD i;
CHAR Name[40];
BOOL bSave;
INT xSize, ySize, xRes, yRes, dx, dy;
RECT Rect;
HFILE fh;
WORD fFileOptions;
UINT id = nID; // replaces id identifier everywhere with value
// of nID (for C++ conversion)
switch (id) {
case IDM_ABOUT:
// code omitted in all cases -- see file SHOWDVW.CPP
case IDM_COPY:
...
case IDM_PASTEPAL:
...
case IDM_PRINT:
...
case IDM_OPEN:
...
case IDM_UPDATECOL:
...
case IDM_DIBSCREEN:
...
case IDM_ANIMATE0:
...
case IDM_STEALCOL:
case IDM_ANIMATE5:
case IDM_ANIMATE20:
...
default:
break;
}
return TRUE;
}
After you move the code over, delete the MenuCommand function in SHOWDIB.CPP and delete the WM_COMMAND case in OnCmdMsg.
The code begins with the familiar HWND replacement code, and most of the code consists of the familiar cases for particular command IDs. The following code:
UINT id = nID;
is similar to the HWND replacement. It maps the nID parameter to the id variable used throughout the code.
The following lines screen out unwanted messages:
if (nCode != 0) // ignore new MFC requests
return FALSE;
The if statement screens out special MFC handling for tasks like updating toolbar buttons. Your OnCmdMsg doesn't deal with such things, so it's best to short circuit the function when such tasks show up.
As usual, you need to disambiguate Windows API calls in OnCmdMsg, either by prefixing the scope resolution operator as shown earlier in WindowProc or by changing them to equivalent MFC member functions (where possible).