14 October 2009

Difference between _Message and _MessageProc

There are two somewhat strange, certainly badly documented, event subs for forms: the Form_Message and Form_MessageProc event. Although they sound much alike, they are quite different. Both events are invoked from inside the window procedure of the form. However _Message() is called only for a handful of messages, but _MessageProc() is called for all messages, regardless of their origin. These subs are defined as:

Sub frm1_Message(hWnd%, Mess%, wParam%, lParam%)
Sub frm1_MessageProc(hWnd%, Mess%, wParam%, 
  lParam%, retval%, ValidRet?)
The _MessageProc event sub With the _MessageProc Sub you can actually filter or influence the behavior of the GB32 window procedure for the Form window class. The _MessageProc is called before GB32 handles the message itself (more or less, maybe later more on this). The sub obtains six message parameters. The first four are the same as defined for a Windows API window procedure. Every message, whether it is obtained from the message queue (the posted messages) or by a direct call from any other source (for instance through SendMessage), is handled in the window procedure. The hWnd parameter is the window to which the message is sent (we already know the objects name: frm and we could obtain the window handle from the object, that would have lowered the number of parameters by one). The Msg parameter is the message number—which is usually a constant such as WM_ACTIVATEAPP or WM_PAINT. The wParam and lParam parameters differ for each message, as does the return value; you must look up the specific message to see what they mean. Often, wParam or the return value is ignored, but not always. The _MessageProc() event sub has two additional parameters (ByRef) that allow you to return a value. For instance, when you want GB32 not to handle a certain message you can set the ValidRet? Boolean variable to True and provide a return value by setting RetVal%. What value RetVal must have is defined in the Windows API SDK. It often says something like: "If you handle this message return zero (or..)". Now let us look at an example. Suppose you want to store the window coordinates of OpenW #1 in the register so the application can use these values to open at the same place. In GB32 you must then handle the sub events Form_ReSize and Form_Moved to store the coordinates. As an alternative you could use Form_MessageProc and handle the WM_EXITSIZEMOVE message as follows:
Sub Win_1_MessageProc(hWnd%, Mess%, wParam%, _

      lParam%, Retval%, ValidRet?)

 Local Int x, y, w, h

 Switch Mess

 Case WM_EXITSIZEMOVE

   GetWinRect hwnd, x, y, w, h

   SaveSetting "MyComp", "ThisApp", "Position",

        Mkl$(x, y, w, h)

   ValiRet? = True : RetVal = 0

 EndSwitch

EndSub
Note the Form_MessageProc() actually _is_ the subclass window procedure for the GB32 windows (Form, Dialog, OpenW, ChildW, ParentW). Subclassing is a built-in feature of GFA-BASIC 32. As such the the OCX control Form is perfectly suited to write custom controls.
The _Message event sub The Form_Message is different: you cannot filter messages and return values, you can only respond to a handful of messages, to WM_SIZE, or WM_PAINT for instance. Why these? Because these are posted messages, messages that are retrieved from the message queue. Note that most posted messages have a accompanying sub event. For instance, a WM_SIZE message results in calling the Form_ReSize event sub. You can use the _Message sub to handle many messages that are otherwise handled in these event subs. All you need to know is which messages are posted. These are all input messages like key and mouse messages, window management messages like moved, sized and wm_paint. You must then, just as in _MessageProc, create a Switch/Case structure to respond to the message. The main disadvantage is that you must interpret the wParam and lParam parameters yourself... The order in which the sub events are called You can easily test in which order the sub events are called. For posted messages, those that are retrieved from the message queue using Sleep, the _Message() event is called before any other sub. Then the message is 'dispatched' to the window procedure and the _MessageProc is called. And at last, the event sub is invoked. For a WM_SIZE message the sequence is: Win_1_Message() Win_1_MessageProc()
Win_1_ReSize (This article was previously posted on the GFA-BASIC Google Pages. It has been edited to remove errors.)

No comments:

Post a Comment