ObjAsm
Search…
⌃K

Dispatching Mechanism

When the OS sends a message, it is processed by the main window procedure that is registered to the OS when a window class is created.
For all applications that derive from SdiApp, MdiApp or DlgApp, this mechanism is completely implemented in the Run and WndProc methods.
The former is the message pump while the second is the dispatcher.
Using a derived from the above mentioned objects has some advantages over regular window procedures since it implements an event method table (EMT) that is used to dispatch the OS messages directly to the handler method. The link between the message ID (e.g. WM_PAINT) and of the handler method is done using the following syntax:
Event OnClick, WM_CLICK
This macro links the procedure OnClick with the event ID WM_CLICK.
It is also possible to link a method to more than one event ID, e.g.:
Event OnClick, WM_CLICK, WM_DBLCLK
When the WndProc method recognises one of these events, the corresponding method is called passing then event ID in the eax register.
Derived objects also inherit the event translation table (ETT) the same way that methods and variables do.
If a handler method is redefined, the new code is called instead of the old method.
All event handler methods must have the same prototype:
Method App.OnClick,, wParam:dword, lParam:dword
MethodEnd
The dispatching mechanism looks like the following code:
Method XXX.WndProc, uses esi, uMsg:dword, wParam:dword, lParam:dword
.if uMsg == WM_NCCREATE
mov eax, lParam
mov esi, [eax].CREATESTRUCT.lpCreateParams
or esi, esi
jz @@DefProc
m2m [esi].SdiApp.hWnd, pSelf
invoke SetWindowLongPtr, pSelf, GWL_USERDATA, esi
.else
invoke GetWindowLong, pSelf, GWL_USERDATA
.if eax == 0
invoke GetWindowLongPtr, pSelf, DWL_USER
or eax, eax
jz @@DefProc
.endif
mov esi, eax
.endif
DispatchEvent <DefWindowProc, pSelf>
MethodEnd
The first thing the procedure does is to check if the received event ID is WM_NCCREATE.
If it is the case, the object instance pointer, which is passed through the CREATESTRUCT structure, is stored in the Window instance USERDATA. In some cases, this is not possible and a Property attached to the Window instance is used to store this information.
If the message is not WM_NCCREATE, the procedure will try to retrieve the object instance pointer. If this is not successful, the default window procedure DefWindowProc is called.
Next, the ETT is searched for the received event ID and the address of the corresponding method is retrieved. This method is called, passing the instance pointer (pSelf), wParam, and lParam as parameters.
The method return value is used as the WndProc return value.

Example

DemoApp02 is a descendant of the SDI application object (SdiApp), which is used as base object for this example. DemoApp02 defines three events with their respective methods:
VirtualMethod OnCommand, LParam, WParam
VirtualMethod OnClose, LParam, WParam
VirtualMethod OnPaint, LParam, WParam
Event OnCommand, WM_COMMAND
Event OnClose, WM_CLOSE, WM_QUERYENDSESSION
Event OnPaint, WM_PAINT The first event method (OnCommand) is triggered each time the WndProc receives a WM_COMMAND message, which can be generated in many ways, i.e. when a menu item is clicked: in this demo, the Exit and About menu items are caught in the OnCommand method.
The first event method (OnCommand) is triggered each time the WndProc receives a WM_COMMAND message, which can be generated in many ways, i.e. when a menu item is clicked: in this demo, the Exit and About menu items are caught in the OnCommand method.
The second event method (OnClose) may be triggered by two messages, WM_CLOSE or WM_QUERYENDSESSION. The method pops up a messagebox asking the user to close the application.
The third event method (OnPaint) is triggered by the WM_PAINT message when the application needs to be redrawn. The method draws the background and an inner edge and fills the client area of the application window.