Do Sleep Loop Until Me Is Nothing
Me is a Form object variable holding the current active window of the GFA-BASIC 32 program. The Me variable always represents the current active window should a program open multiple windows. Me always represents a window (Form) unless the last window is closed, then Me is equal to Nothing. That’s the moment the Do loop is ends and the program stops.
GFA-BASIC 32 offers 4 different commands to read the message loop and dispatch the message to the appropriate window procedure. Essentially, all these commands utilize PeekMessage(), TranslateMessage(), and DispatchMessage() - like any other message loop under Windows. They only slightly differ which I will discuss here. Let’s start with PeekEvent because it is the heart of all four commands.
PeekEvent invokes the PeekMessage(V:msg,0,0,0,PM_REMOVE) function, which checks a thread message queue for a message and places the message (if any) in the specified structure. If no messages are available, the return value is zero. The PM_REMOVE flag indicates that messages are removed from the queue after processing by PeekMessage. The following GB32 listing shows pseudo-code for the PeekEvent command.
Procedure PeekEvent() Dim msg As MESSAGE // Clear MENU() event array MemZero(MENU(0), 17) // Obtain message if available If PeekMessage(V:msg, 0, 0, 0, PM_REMOVE) // Copy msg members to MENU() array MENU(2) = msg.pt.x MENU(3) = msg.pt.y MENU(16)= msg.time // Handle key input messages If msg.message >= WM_KEYFIRST && _ msg.message <= WM_KEYLAST // Handle keyboard events at // the application level. Exit Sub If Screen_KeyPreview(V:msg) // If Name starts with 'Dlg_' use // special IsDialogMessage(). If Me.IsDialog Then IsDlg_XX_Message(Me.hWnd, V:msg) Else ~TranslateMessage(V:msg) EndIf EndIf // Send to appropriate window proc ~DispatchMessage(V:msg) EndIf // PeekMessage() EndProc
This pseudo code is rather accurate. I omitted the check for reentrance while executing PeekEvent. Only this, once PeekEvent is executing and is dispatching messages, it cannot be reentered again.
- GetEvent is a simple variation on PeekEvent. Like PeekEvent it only retrieves one message a time and then returns to the application, in fact GetEvent invokes PeekEvent as follows:
Procedure GetEvent() If Not GetQueueStatus(QS_ALLEVENTS) Then _ ~WaitMessage() @PeekEvent() EndProc
GetEvent waits for a message when - on entrance - no messages are current in the queue. When a message is available it calls PeekEvent to handle the message and then returns to the application.
-DoEvents is a VB compatible command (used seldom in VB because the message loop is hidden and executed automatically in VB programs). In GB32 it is implement as a loop calling PeekEvent until the message queue is empty.
Function DoEvents%() Dim Count% = 0 While @PeekEvent() Count% ++ Wend ~Sleep(Count%) Return Count% EndFunc
DoEvents yields execution for a small amount of time after retrieving all messages form the queue. It returns the number of messages obtained. The yielding time depends on the number of handled messages.
- Sleep starts with calling DoEvents. When DoEvents returns 0 then Sleep goes in a wait state and waits for new messages and when they arrive it executes DoEvents again.
Procedure Sleep() If @DoEvents%() = 0 Then ~WaitMessage() @DoEvents%() EndIf EndProc
Sleep is the preferred command for the main message loop of course.