Pelles C forum

C language => Tips & tricks => Topic started by: NormC on June 19, 2014, 05:20:20 PM

Title: Generic Code for Replacing Message Procedures
Post by: NormC on June 19, 2014, 05:20:20 PM
I came across a method to use a generic set of code for Windows Message Procedures
(MainWndProc and DialogWndProc) as well as the command message processing within these.

It was discussed by Nancy Cluts in her book on programming Windows 95 but is still applicable and neatly replaces the if or switch coding used in most coding with a table of message values and function pointers.

I believe the biggest problem for most programmers is the definition of the table entries.

For this I use two typedef statements:

Code: [Select]
typedef int (*hndlr)(); // HWND, WPARAM, LPARAM is needed for arguments in older versions
  // note also that *hndlr is in brackets to insure correct typing

typedef struct msgentry {
int    iMsgValue; // value of message to process
hndlr pFnCalled; // pointer to function handling the message
} MsgEntry;
It should be noted that commands can be handled by the same structure by replacing message values and function pointers with command values and function pointers.

Using the Hello Program created by the Application Wizard as an example:

Code: [Select]
/* All handler functions return an int value */

int About_OnCancel(HWND hDlg, WPARAM wParam, LPARAM lParam);

MsgEntry AboutCmdTable[] = {{IDOK,     About_OnCancel},
                            {IDCANCEL, About_OnCancel},
    {-1, NULL}};

int About_OnInit(HWND hwnd, WPARAM wParam, LPARAM lParam);
int About_OnCommand(HWND hwnd, WPARAM wParam, LPARAM lParam); // See description after function below.

MsgEntry AboutMsgTable[] = {{WM_COMMAND,    About_OnCommand},
                            {WM_INITDIALOG, About_OnInit},
    {-1, NULL}};

LRESULT AboutDlgProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
int iTableIndex = 0;
int iReturnValue = 0;

while (AboutMsgTable[iTableIndex].iMsgValue != -1)
        {
if (AboutMsgTable[iTableIndex].iMsgValue == uMsg)
   {
   iReturnValue = AboutMsgTable[iTableIndex].pFnCalled (hDlg, wParam, lParam);
   break;
   }
else
   iTableIndex++;
}
if (AboutMsgTable[iTableIndex].iMsgValue == -1)
   iReturnValue = FALSE;

return iReturnValue;
}
The body of the function above can be used for any dialog related message or command processing. Here changing the table from AboutMsgTable to AboutCmdTable gives the body of About_OnCommand.

Code: [Select]
int Menu_About(HWND hwnd, WPARAM wParam, LPARAM lPsrsm);

MsgEntry MainCmdTable[] = {{IDM_ABOUT, Menu_About},
  // TODO: Add more commands and functions here
    {-1,         NULL}}; // End of data marker

int Main_OnPaint(HWND hwnd);
int Main_OnDestroy(HWND hwnd)
int Main_OnCommand(HWND hwnd, WPARAM wParam, LPARAM lParam); // See description after function below.

MsgEntry MainMsgTable[] = {{WM_COMMAND, Main_OnCommand},
           {WM_PAINT,   Main_OnPaint},
    {WM_DESTROY, Main_OnDestroy},
    // TODO: Add more messages and functions here
    {-1,         NULL}}; // End of data marker

LRESULT CALLBACK MainWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
int iTableIndex = 0;
int iReturnValue = 0;

while (MainMsgTable[iTableIndex].iMsgValue != -1)
      {
      if (MainMsgTable[iTableIndex].iMsgValue == msg)
{
iReturnValue = MainMsgTable[iTableIndex].pFnCalled (hwnd, wParam, lParam);
break;
}
      else
iTableIndex++;
      }
      if (MainMsgTable[iTableIndex].iMsgValue == -1)
iReturnValue = DefWindowProc(hwnd, msg, wParam, lParam);

return iReturnValue;
}

The body of the function above can be used for any window related message or command processing. Here changing the table from MainMsgTable to MainCmdTable gives the body of Main_OnCommand.