Windows system callbacks are fully implemented. The user may specify a callback with any number of parameters. The parameters are passed to a SwiftForth function on the Windows original stack frame and may be accessed via a set of predefined (and user extensible) names in any routine responding to the callback, similar in principle to local variables. There is no requirement for the parameters to be carried around on the stack to each routine in the response code. For example, to enumerate all fonts in the system:
: SHOWFONT ( -- res ) HWND MSG WPARAM LPARAM FontFunc 1 ; ' SHOWFONT 4 WP: &SHOWFONTS : .FONTS ( -- ) HCON GetDC 0 &SHOWFONTS 0 EnumFonts ;
This code snippet defines a four-parameter Windows callback named &SHOWFONTS, which calls the Forth routine SHOWFONT. When SHOWFONT executes, it has free access to the four parameters passed to it via the built-in names HWND MSG WPARAM and LPARAM. The function .FONTS passes the address of &SHOWFONTS to the Windows API function EnumFonts as the address for the callback.
SwiftForth's console debugging tool can be used to trace the execution of Windows callbacks, as the console is completely independent of Windows' GUI interface.
System messages are handled via a compiled switch mechanism, which is extensible by the user to include any new messages that need to be handled. For example, this is the code to extend the standard existing Windows message handler SFMESSAGES to include keystroke events:
[+SWITCH SFMESSAGES
WM_SYSKEYDOWN RUNS KDOWN1
WM_KEYDOWN RUNS KDOWN0
WM_CHAR RUNS CDOWN0
WM_SYSCHAR RUNS CDOWN1
SWITCH]
Dialog boxes are supported via a simple dialog compiler, which parallels the Microsoft resource compiler. SwiftForth's console debugging tool can be used to trace the execution of Windows dialog box code.
A simple example of a dialog box is:
OPTIONAL SIMPLE A modal dialog template which uses catch/throw.
{ ====================================================================
(C) Copyright 1999 FORTH, Inc. www.forth.com
SIMPLE Dialog box example
==================================================================== }
DIALOG (SIMPLE) [MODAL " Press counter" 10 10 160 40
(FONT 8, MS Sans Serif) ]
\ [control " default text" id xpos ypos xsiz ysiz ]
[DEFPUSHBUTTON " OK" IDOK 105 20 45 15 ]
[PUSHBUTTON " Clear" 103 05 20 45 15 ]
[PUSHBUTTON " Throw" 104 55 20 45 15 ]
[RTEXT 101 05 05 18 10 ]
[LTEXT " Total errors" 102 25 05 50 10 ]
END-DIALOG
: SIMPLE-CLOSE ( -- res ) HWND 0 EndDialog ;
VARIABLE PRESSES
: .PRESSES ( -- ) HWND 101 PRESSES @ 0 SetDlgItemInt DROP ;
: THROWING ( -- ) -1 THROW ;
: STUPID ( -- ) ['] THROWING CATCH IF PRESSES ++ .PRESSES THEN ;
[SWITCH SIMPLE-COMMANDS ZERO ( -- res )
IDOK RUN: SIMPLE-CLOSE ;
IDCANCEL RUN: SIMPLE-CLOSE ;
103 RUN: PRESSES OFF .PRESSES 0 ;
104 RUN: STUPID 0 ;
SWITCH]
[SWITCH SIMPLE-MESSAGES ZERO
WM_CLOSE RUNS SIMPLE-CLOSE
WM_INITDIALOG RUN: ( -- res ) 0 PRESSES ! .PRESSES -1 ;
WM_COMMAND RUN: ( -- res ) WPARAM LOWORD SIMPLE-COMMANDS ;
SWITCH]
:NONAME ( -- res ) MSG LOWORD SIMPLE-MESSAGES ; 4 CB: RUNSIMPLE
: SIMPLE
HINST (SIMPLE) HWND RUNSIMPLE 0 DialogBoxIndirectParam DROP ;
CR CR .( Type SIMPLE to run the dialog sample.) CR CR