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));
		}