Author Topic: 4b. Messages and Message Handlers  (Read 879 times)

0 Members and 1 Guest are viewing this topic.

Offline LarryMc

  • Administrator
  • Hero Member
  • *****
  • Posts: 5934
  • 'All I like is finishing'
4b. Messages and Message Handlers
« on: July 28, 2011, 08:08:31 AM »
Part B

Now we turn our attention back to windows based programs.  Any program that uses windows automatically, by its very nature, becomes an event driven program. When we create our windows application it has to coexist with other windows based applications. Your PC desktop is a windows application, as is windows explorer and any other application you might have running. 

Consider, for example, that you have your prize application open along with windows explorer. You only created your application; not the other.  Assume you have been using your application (it is on top of the other) and you want to locate a file in windows explorer. You click on the explorer window. The operating system responds to that click event by sending a message to the explorer window which ultimately causes it to be drawn on top. A message is also sent to your application telling it that it is no longer on top and don't redraw its window where it is covered. The operating system was able to accomplish that by recognizing what window contains the pixel on the screen that the cursor was on when the mouse button was clicked. It then sends the various event messages to all the required message handlers.

The operating system system contains 1,000s of messages.  They indicate a wide range of events. Examples include  events due to user interaction, network traffic, system processing, and timer activity, Messages can even indicate that an event is starting to occur, occurring, starting to finish occurring, and has finished occurring.  And remember, from earlier, these messages are nothing more than a numeric value representing a specific event.

From the IWBasic Windows section we learned that we had to specify a handler routine for our window when we created it.  Take the following example:
ex_4.iwb
Code: [Select]
DEF w1 as WINDOW
OPENWINDOW w1,0,0,350,350,@MINBOX|@MAXBOX|@SIZE,NULL,"Simple Window",&main
WAITUNTIL w1 = 0
END

SUB main
IF @MESSAGE = @IDCLOSEWINDOW
CLOSEWINDOW w1
ENDIF
RETURN 0
ENDSUB
The above is the simplest windows program you can write in IWBasic. If you compile it to a Windows target and then  execute it, a window with a white background will appear in the upper left corner of your screen.  It can be minimized, maximized, resized, repositioned and closed.

Let's examine each line of the program.

Code: [Select]
DEF w1 as WINDOW
We define a variable, w1, as being UDT type WINDOW as previously described.
_____________

Code: [Select]
OPENWINDOW w1,0,0,350,350,@MINBOX|@MAXBOX|@SIZE,NULL,"Simple Window",&main
We create our window and identify our handler subroutine as 'main'.
_____________

Code: [Select]
WAITUNTIL w1 = 0
When a window is created in IWBasic the first element of the WINDOWS UDT (hWnd) is assigned the handle number that the windows OS assigned to that specific window when it was created.  This handle is used by the OS to identify what message goes to what window.  More about this later.  For now suffice it to say that w1 will be some non-zero value when the window is created.  The WAITUNTIL command is a loop that waits for the window to close as signified by w1 equaling zero.  If you remark out this instruction and recompile the program you will see that the window will momentarily flash open and  then disappear.  That's because without this loop the program continues execution to the next statement.
Note: Another way to do the exact same thing is:

Code: [Select]
WAITUNTIL IsWindowClosed(w1)______________

Code: [Select]
END
Stops program execution when it is encountered.
______________

Newbie's at this point might ask, "where 's the call to the 'main' subroutine?  It appears that it is not being used.  And the 'main' subroutine has no parameters"

This is where some of the internal magic of IWBasic, and the OS, comes into play.  As messages are generated and sent to an IWBasic window they are automatically passed to the handler routine.  Because of that, there is no need for declared passed parameters in the handler SUB statement.  By the same token, there is a returned value from the handler subroutine even though the SUB declaration doesn't specify one is required.

Let's look at each line of our simple handler routine above.

Code: [Select]
SUB main
The subroutine declaration for our handler routine.
______________

Code: [Select]
IF @MESSAGE = @IDCLOSEWINDOW
This line is testing to see if the IWBasic system variable @MESSAGE contains a value that is equal to the IWBasic system constant @IDCLOSEWINDOW.  If the condition is true the next statement is executed; otherwise it is skipped.
______________

Code: [Select]
CLOSEWINDOW w1
This command closes the window and sets the window handle wHnd element of the WINDOW UDT for w1 to zero. When that occurs the WAITUNTIL loop discussed above will be true and the program will end.
______________

Code: [Select]
ENDIF

Marks the end of the IF block.
______________

Code: [Select]
RETURN 0
The standard return from the handler subroutine with the normal value of zero
______________

Code: [Select]
ENDSUB
Marks the end of the handler subroutine.
______________

There are a couple of points that can be made with this example. The first is that the reader should be able to see why I said earlier that the old DOS example was an example of a crude handler; specifically the example that only had the test for the 'Q' key being pressed (ex_2.iwb).  In that example we where focusing on only one specific event and disregarding all other events.  The same is happening with this simple windows example.

A second point is that we wrote no code associated with the button in the caption bar that we use to close the window.  That code has to exist somewhere or the button would not cause that specific message to be sent.  As our discussion continues that will be covered.

Also, we know that there are other ways to close the window; in task manager by stopping the process or my shutting down the computer which in turn closes our example program.  The point being, as described earlier, that messages for a specific window can come from different places.

At this point, we need to explore the following line again.

Code: [Select]
IF @MESSAGE = @IDCLOSEWINDOW
As previously stated, @MESSAGE is an IWBasic system variable which will contain a message ID.  It is valid only inside a handler subroutine.  In the past the IWBasic system variable @CLASS was used to hold the exact same information.  They may be freely interchanged with each other.

Also, @IDCLOSEWINDOW is an IWBasic system constant.  It's pre-assigned value is the same as the Windows OS message WM_CLOSE. They may be freely interchanged also.  There are numerous OS message IDs that have had IWBasic system constants pre-assigned for them.  In every case the user may substitute one for the other.
It must be noted that in order to use these non-IWBasic system constants the user will have to define them and assign the proper value.  This step is not required if the user include's Sapero's 'windowssdk.inc' in the user's source file where that has already been taken care of.

------
the next section will continue the messages and handlers discussion

LarryMc
LarryMc
Larry McCaughn :)
Author of IWB+, Custom Button Designer library, Custom Chart Designer library, Snippet Manager, IWGrid control library, LM_Image control library