PDA

View Full Version : EventShaper - experimental module to wrap ugly Win32 messages into user defined form



Petr Schreiber
08-05-2012, 15:34
The idea
Handling window messages can be done in multiple ways - by reading the state asynchronously, in tight message pumps, using callback mechanisms - ThinBASIC has it all.
While experimenting with more heavily GUI based languages, I realised the approach "one event -> one procedure" is another quite nice way to manage things.

The most common approach in ThinBASIC now is using callbacks - it is fast, it is quite elegant, but still - you usually end with SELECT CASE of epic proportions, handling Win32 dark magic such as wParam and lParam.
To give an example, here little demo:


callback function dlgCallback() as long
select case msg
case %WM_LBUTTONDOWN
Long x = LO(WORD, cblParam)
Long y = HI(WORD, cblParam)
...


It works, it is standard, but it can be a bit cryptic sometimes and when the SELECT CASE grows too much, the program tends to be slightly noodle like.

I was thinking about creating something like a mixture between the power of direct Win32 access and the high levelity seen for example in C#.

The possible approach
My first attempt is lightweight module called simply EventShaper. It allows to subscribe for processing of various events in way which is more human friendly than Win32 in the end (of course, subjective feeling).

How does this work?

Step 1: You define wrapper from Win32 to TYPE of your choice, directly in ThinBASIC

you do this once, and it can be used in multiple projects later


Step 2: You define custom event handling routines, which use the "nice" syntax


To give you better idea, here is sample code:


'
' Simple test of Event Shaper
' Created by Petr Schreiber, 2012
'

#MINVERSION 1.9.0.0

Uses "UI", "EventShaper"
Uses "Console"

#INCLUDE "Wrapper_Definitions.tBasicI"

' -- Create dialog here
Function TBMain()
Local hDlg As DWord

Dialog New Pixels, 0, "Click on this window",-1,-1, 320, 240, _
%WS_POPUP Or %WS_VISIBLE Or %WS_CAPTION Or %WS_SYSMENU Or %WS_MINIMIZEBOX To hDlg

EventShaper_SubscribeWindowEvent(hDlg, %WM_LBUTTONDOWN, "Main_OnLButtonDown")
EventShaper_SubscribeWindowEvent(hDlg, %WM_LBUTTONUP , "Main_OnLButtonUp")
EventShaper_SubscribeWindowEvent(hDlg, %WM_CLOSE , "Main_OnClose")

Dialog Show Modal hDlg, Call cbDialog

End Function

' -- Event handler of OnLButtonDown receives data in nice form
Function Main_OnLButtonDown()

' -- Single line to retrieve all the parameters
Dim eArgs As tEvent_OnLButtonDown At EventShaper_GetEventArguments()

' -- We can look them up and print out to console
PrintL "OnLButtonDown"
PrintL "hWnd", eArgs.hWnd
PrintL "X", eArgs.x
PrintL "Y", eArgs.y
PrintL

End Function

' -- Event handler of OnLButtonUp receives data in nice form
Function Main_OnLButtonUp()

' -- Single line to retrieve all the parameters
Dim eArgs As tEvent_OnLButtonUp At EventShaper_GetEventArguments()

' -- We can look them up and print out to console
PrintL "OnLButtonUp"
PrintL "hWnd", eArgs.hWnd
PrintL "X", eArgs.x
PrintL "Y", eArgs.y
PrintL

End Function

Function Main_OnClose()

MsgBox 0, "Yeah, yeah, I will quit now..."

End Function

' -- Callback for dialog - still needed, not sure why
CallBack Function cbDialog()

End Function


As you can see, it looks quite straightforward and the program is not complicated with much Win32 specifics.

The example above does not show the wrapping part, because that is the thing you do typically once, keep that ugly beast in separate include file and never look at it again :)
The wrapping is 100% under programmer control. Here example for WM_LBUTTONDOWN:


'[!] WM_LButtonDown

' -- Completely custom type
Type tEvent_OnLButtonDown
hWnd As DWord
x As Long
y As Long
End Type

' -- Wrapper routine
Function Wrapper_WM_LBUTTONDOWN()

' -- Retrieve the needed Win32 params (EventShaper engine picks them for you)
DWord hWnd, wParam, lParam
EventShaper_GetWrapperParams(hWnd, wParam, lParam)

' -- Process them to human readable form
Dim event As tEvent_OnLButtonDown
event.hWnd = hWnd
event.x = LO(Word, lParam)
event.y = HI(Word, lParam)

' -- Pack them for the event handler in nice form
EventShaper_SetEventArguments(event)

' -- EventShaper module will call the appropriate high level routine when ready
End Function
' -- Link the routine
EventShaper_SetWrapper(%WM_LBUTTONDOWN, "Wrapper_WM_LBUTTONDOWN")


In ideal world, the module would do this wrapping internally - but doing this for whole Win32 range of messages would have these disadvantages:

It would take lot of time to prepare (the module as is took 1 day to prepare)
It would mean having the events hardwired, adding others would mean recompiling the module
It would force the user to accept one and only way the parameters are organised


The approach now is more free in the way you can add any event you want and publish the data from it in way which you like most (because how will the TYPE with data look is completely up to you).
The wrapper setup and window-procedure binding is separate, which means you can reuse the wrapper include later in other project, as it won't contain any project specific code.

Module functions
There are two functions for specifying the Win32 message wrapper:

EventShaper_SetWrapper(BYVAL Win32Message AS DWORD, BYVAL wrapperFunction AS FUNCTION)

Specifies wrapper function for given Win32 message


EventShaper_ClearWrapper(BYVAL Win32Message AS DWORD)

Cancels wrapper function for given Win32 message


Then there are two functions to be used inside the wrapper function on ThinBASIC side:

EventShaper_GetWrapperParams(BYREF hWnd AS DWORD, BYREF wParam AS DWORD, BYREF lParam AS DWORD)

Allows wrapper function to retrieve the hWnd, wParam and lParam


EventShaper_SetArguments(BYVAL param AS ANY)

Allows wrapper function to pass out the processed parameters


Then one function to retrieve the parameters in the event handler:

EventShaper_GetArguments() AS DWORD

Allows event function to retrieve the processed parameters


And of course, the last but not least, functions to actually link the particular window to high level event handler:

EventShaper_SubscribeWindowEvent(BYVAL hWnd AS DWORD, BYVAL Win32Message AS DWORD, BYVAL eventFunction AS FUNCTION)

Subscribes wrapped processing for passed window


EventShaper_UnSubscribeWindowEvent(BYVAL hWnd AS DWORD, BYVAL Win32Message AS DWORD, BYVAL eventFunction AS FUNCTION)

Unsubscribes wrapped processing for passed window


Demo + Source code
You will probably need ThinBASIC 1.9.0.0 to try this out: http://www.thinbasic.biz/projects/thinbasic/thinBasic_1.9.0.0.zip

The attachement contains:

Simple demo application with module attached
Full source code for PB/WIN 9


Please note this is the first version, so the chance to find a bug is quite high and there is not really much error checking done yet.

Let me know what you think about it!


Petr

Oscar Ugolini
08-05-2012, 23:55
I will test it...
I want compare this "new" event control concept with the "standard" select-case, to check how it works on input message back (mouse, keyboard...)... especially during graphic render ( TBGL :) )
nice idea Petr... "I hate SELECT-CASE!!!" :)
bye
Oscar

Petr Schreiber
09-05-2012, 10:59
Hi Oscar,

I updated the first post with example for TBGL (EventShaper_TestApplicationForTBGL.zip).

It shows how to catch the mouse messages and how to convert the 2D coordinates of mouse to 3D coordinates of place you clicked on. Try to click on the cube to see the listing in the console.


Petr

Oscar Ugolini
09-05-2012, 12:51
thanks!
:)
oscar

Lionheart008
09-05-2012, 18:33
hi petr, looks interesting with eventshaper and good idea to prevent select case mess. Wanna test it, but where I can find the new 1.9.9.0 beta of thinbasic? ;) beste grüße, frank

this link could be right adress, but cannot find it: http://www.thinbasic.com/community/forumdisplay.php?206-Announcements

Petr Schreiber
09-05-2012, 19:35
Hi Frank,

the link to version 1.9.0.0 is in the first post, I will repeat it here:
ThinBASIC 1.9.0.0 beta (http://www.thinbasic.biz/projects/thinbasic/thinBasic_1.9.0.0.zip)

I don't consider the callback mechanism with Select Case a mess - in fact it is very nicely structured, but sometimes you want to focus on what you need rather than studying Win32 in depth.


Petr