Message Crackers

[Previous] [Next]

Message crackers make it easier to write window procedures. Typically, window procedures are implemented as one huge switch statement. In my travels, I've seen window procedure switch statements that contained well over 500 lines of code. We all know that implementing window procedures in this way is bad practice, but we do it anyway. I've been known to do it myself on occasion. Message crackers force you to break up your switch statements into smaller functions—one function per window message. This makes your code much more manageable.

Another problem with window procedures is that every message has wParam and lParam parameters, and depending on the message, these parameters have different meanings. In some cases, such as a WM_COMMAND message, wParam contains two different values. The high-word of the wParam parameter is the notification code, and the low-word is the ID of the control. Or is it the other way around? I always forget. If you use message crackers, you don't have to remember or look up any of this. Message crackers are so named because they crack apart the parameters for any given message. To process the WM_COMMAND message, you simply write a function that looks like this:

 void Cls_OnCommand(HWND hwnd, int id, HWND hwndCtl, UINT codeNotify) { switch (id) { case ID_SOMELISTBOX: if (codeNotify != LBN_SELCHANGE) break; // Do LBN_SELCHANGE processing. break; case ID_SOMEBUTTON: break;  } } 

Look how easy it is! The crackers look at the message's wParam and lParam parameters, break the parameters apart, and call your function.

To use message crackers, you must make some changes to your window procedure's switch statement. Take a look at the window procedure here:

 LRESULT WndProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { switch (uMsg) { HANDLE_MSG(hwnd, WM_COMMAND, Cls_OnCommand); HANDLE_MSG(hwnd, WM_PAINT, Cls_OnPaint); HANDLE_MSG(hwnd, WM_DESTROY, Cls_OnDestroy); default: return(DefWindowProc(hwnd, uMsg, wParam, lParam)); } } 

The HANDLE_MSG macro is defined as follows in WindowsX.h:

 #define HANDLE_MSG(hwnd, message, fn) \ case (message): \ return HANDLE_##message((hwnd), (wParam), (lParam), (fn)); 

For a WM_COMMAND message, the preprocessor expands this line to read as follows:

 case (WM_COMMAND): return HANDLE_WM_COMMAND((hwnd), (wParam), (lParam), (Cls_OnCommand)); 

The HANDLE_WM_* macros, which are also defined in WindowsX.h, are actually message crackers. They crack the contents of the wParam and lParam parameters, perform all the necessary casting, and call the appropriate message function, such as the Cls_OnCommand function shown earlier. The macro for HANDLE_WM_COMMAND is as follows:

 #define HANDLE_WM_COMMAND(hwnd, wParam, lParam, fn) \ ( (fn) ((hwnd), (int) (LOWORD(wParam)), (HWND)(lParam), (UINT) HIWORD(wParam)), 0L) 

When the preprocessor expands this macro, the result is a call to the Cls_OnCommand function with the contents of the wParam and lParam parameters broken down into their respective parts and cast appropriately.

Before you use message cracker macros to process a message, you should open the WindowsX.h file and search for the message you want to process. For example, if you search for WM_COMMAND, you'll see the part of the file that contains these lines:

 /* void Cls_OnCommand(HWND hwnd, int id, HWND hwndCtl, UINT codeNotify); */ #define HANDLE_WM_COMMAND(hwnd, wParam, lParam, fn) \ ((fn)((hwnd), (int)(LOWORD(wParam)), (HWND)(lParam), \ (UINT)HIWORD(wParam)), 0L) #define FORWARD_WM_COMMAND(hwnd, id, hwndCtl, codeNotify, fn) \ (void)(fn)((hwnd), WM_COMMAND, \ MAKEWPARAM((UINT)(id),(UINT)(codeNotify)), \ (LPARAM)(HWND)(hwndCtl)) 

The first line is a comment that shows you the prototype of the function you have to write. The next line is the HANDLE_WM_* macro, which we've already discussed. The last line is a message forwarder. Let's say that during your processing of the WM_COMMAND message you want to call the default window procedure to have it do some work for you. This function would look like this:

 void Cls_OnCommand (HWND hwnd, int id, HWND hwndCtl, UINT codeNotify) { // Do some normal processing. // Do default processing. FORWARD_WM_COMMAND(hwnd, id, hwndCtl, codeNotify, DefWindowProc); } 

The FORWARD_WM_* macro takes the cracked message parameters and reconstructs them to their wParam and lParam equivalents. The macro then calls a function that you supply. In the example above, the macro calls the DefWindowProc function, but you can just as easily use SendMessage or PostMessage. In fact, if you want to send (or post) a message to any window in the system, you can use a FORWARD_WM_* macro to help combine the individual parameters.



Programming Applications for Microsoft Windows
Programming Applications for Microsoft Windows (Microsoft Programming Series)
ISBN: 1572319968
EAN: 2147483647
Year: 1999
Pages: 193

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net