programming tools for Windows applications development
  Home  |   SwiftForth Archive  |   SwiftX Archive  |

Callbacks -- part 2

From: Rick VanNorman <rick_at_forth.com>
Date: Tue, 13 Nov 2001 21:29:48 -0800

----------------------------------------------------------------------
Callbacks, part 2
----------------------------------------------------------------------

Last time I explored what CB: compiled in the dictionary. Tonight, we'll
be looking at the behavior of RUNCB. This is a more complicated issue,
so please bear with me.

When a callback is invoked by Windows, the cpu knows nothing about the
SwiftForth processor model or memory allocations or dictionary or
anything else. So, if we want to run a SwiftForth word, we must
establish all of that context as soon as the callback is run. This is
the function of RUNCB.

We want to execute a Forth word to handle the callback, and words are
specified by their XT. So, we have to convey the XT to run to the callback.
This is the purpose of the CALL RUNCB compiled by CB: .

Here is the code I want to examine tonight. It simply counts all of
the application windows known to the operating system.

----------------------------------------------------------------------

{ --------------------------------------------------------------------
HOW-MANY is a variable holding a count.
COUNT-WINDOWS increments the count and returns TRUE.
The line defining ALLWINDOWS compiles the following code:

      ALLWINDOWS:
               CALL DOCREATE
      ALLWINDOWS-DATA:
               CALL RUNCB
               RET #8
               NOP
               DW XT-OF-COUNT-WINDOWS

TEST zeros the counter, calls the EnumWindows api, and returns a count.
-------------------------------------------------------------------- }

VARIABLE HOW-MANY

: COUNT-WINDOWS ( -- flag ) 1 HOW-MANY +! 1 ;

' COUNT-WINDOWS 2 CB: ALLWINDOWS

: TEST ( -- ) 0 HOW-MANY !
   ALLWINDOWS 0 EnumWindows DROP HOW-MANY @ ;

----------------------------------------------------------------------

When we execute TEST, the address of ALLWINDOWS (which is an absolute
address of pure machine code that Windows can execute) is pushed onto
the datastack, along with a zero. This is in accordance to the api
specified for EnumWindows().

EnumWindows() immediately executes the callback code, building for it a
WINAPI stack frame on the processor stack. SwiftForth uses the processor
stack for its return stack -- and yes, that's where this callback is
built. We don't know where on our return stack, only that it is
guaranteed by the processor model not to overwrite the data already on
the stack. Pushed onto the stack is the zero (which could be any data
that TEST wanted to pass to the callback function) and a return address
in the Windows kernel. Execution of this portion begins at ALLWINDOWS
with a clean processor context with only an initialized processor
stack. All other registers must be assumed to be uninitialized.

On my system, when ALLWINDOWS is executed, the return stack has the
following content:

   77E16661 <top the return address in the windows kernel
   002B013E <top+4 the handle of the window which is being enumerated
   00000000 <top+8 the optional parameter passed to EnumWindows

Then, RUNCB is called, which leaves the return stack looking like

   0046E9A9 <top the address of ALLWINDOWS-DATA
   77E16661 <top+4 the return address in the windows kernel
   002B013E <top+8 the handle of the window which is being enumerated
   00000000 <top+12 the optional parameter passed to EnumWindows

Next time, we'll pick up here and see what RUNCB actually does.

Thanks for listening.

Rick

P.S. Please give feedback! Especially on things that aren't clear or
need more explainations. If you only want to say "good job" or other
very nice things that make me smile, please send those privately, not on
the list. Let's keep the bandwidth here for Forth content.

P.P.S. Not all callbacks are immediate; some wait for events triggered
by asychronous events such as the mouse or keyboard, others wait for
specified times, still others wait for I/O completion. We'll discuss
these later.

----------------------------------------------------------------------
sftalk_at_forth.com The SwiftForth programming discussion email list
To unsubscribe, send subject "unsubscribe sftalk" to listar_at_forth.com
For help with listar commands, send subject "help" to listar_at_forth.com
Archives are located at http://www.forth.com/sftalk -- check them out!
Search the archives! Visit http://www.forth.com/search for details.
Received on Tue Nov 13 2001 - 21:29:05 PST

This archive was generated by hypermail 2.2.0 : Fri Nov 21 2008 - 03:04:19 PST