Sub-Classing Windows

The CMACW macro language provides a method to subclass a window so that you may customize a windows action to the fullest extent. Those of you familiar with Windows programming can understand how powerful a feature like this can be. It allows the macro language to fully customize any windows action by intercepting the messages destined for it. The syntax for sub-classing is :
        SubClass_With_Macro (int window_handle,
                             str macro_name,
                             str additional_params);
where window_handle is the HWND of the window, macro_name is the name of the macro to execute for the window sub-class and additional_params is a string which may contain any added information to be passed to the window sub-class macro. The window sub-class macro must be of the type:
        int macro_proc (int &retval,
                        int window,
                            wparam,
                            lparam,
                        str params);
where retval is the value of the message, window the HWND of the window, wparam, lparam are specific to each message and params is what you passed to the Subclass_with_Macro statement.

In order to show some of this power I have written a little macro sub-class that will log the Windows messages for a Multi-Edit buffer window to a file. This is similar to programs such as Winsight for Borland.

int MsgLogProc (int &retval, int window, message, wparam, lparam, str parms) {
  int rv = 0;
  int tw = cur_window;
  int lognum = parse_int ("/MSGLOG=", parms);

  int tr = Refresh;
  Refresh = False;

  // switch to log
  if(!switch_win_id(global_int("~MSGLOG-"+str(lognum))))
  { return (rv); }

  str message_text;
  eof;   // if not a beginning the go down a line.
  if (c_col > 1) down;

  switch ( message )
  {
    case 0x0000 : message_text = "wm_Null"; break;
    case 0x0001 : message_text = "wm_Create"; break;
    case 0x0002 : message_text = "wm_Destroy"; break;
    case 0x0003 : message_text = "wm_Move"; break;
    case 0x0005 : message_text = "wm_Size"; break;
    case 0x0006 : message_text = "wm_Activate"; break;
    case 0x0007 : message_text = "wm_SetFocus"; break;
    case 0x0008 : message_text = "wm_KillFocus"; break;
    case 0x000A : message_text = "wm_Enable"; break;
    case 0x000B : message_text = "wm_SetRedraw"; break;
    case 0x000C : message_text = "wm_SetText"; break;
    case 0x000D : message_text = "wm_GetText"; break;

   // insert here other cases

    default:
        if(message >= 0x400)
        {
          message_text = "wm_user + 0x" + hex_str(message - 0x400);
        }
        else
        {
          message_text = "unknown 0x" + hex_str(message);
        }
  }

  pad_str ( message_text, 22, " " );
  str wp[6]  = hex_str (wparam & 0xffff),
      lp[10] = hex_str (lparam) ;

  wp = copy("0000", 1, 4 - svl(wp) ) + wp;
  lp = copy("00000000", 1, 8 - svl(lp) ) + lp;
  put_line( hex_str (window) + ": " +
        caps( message_text ) +
        " WP: 0x" + wp +
        "  LP: 0x" + lp );

  switch_window (tw);
  Refresh = tr;
  return (rv);
}

void Message_Log (int lognum, int window)
{
  int tw = cur_window;
  int tr = refresh;
  refresh = False;

  // see if it exists
  if(!switch_win_id(global_int("~MSGLOG-"+str(lognum))))
  {
    rm ("CreateWindow");
    set_global_int("~MSGLOG-" + str(lognum), window_id);
    file_name = "MSG-" + str(lognum) + ".LOG";
  }
  switch_window (tw);
  refresh = tr;
  subclass_with_macro (window, "MsgLogProc", "/MSGLOG=" + str(lognum));
}