=====Using callback functions=====
//by Richard Russell, December 2008//\\ \\ A few **Windows API** functions require the use of a **callback** routine, that is a function which you provide that is called by Windows during execution of the API call. The normal [[http://www.bbcbasic.co.uk/bbcwin/manual/bbcwin7.html#sys|SYS]] statement does not provide this capability, but it is available by means of the **CALLBACK** library provided with //BBC BASIC for Windows//.\\ \\ The library should be installed, as usual, by including this code at the beginning of your program, for example in an initialisation routine:
INSTALL @lib$+"CALLBACK"
To use the library, replace the conventional method of calling a Windows API function:
SYS "FunctionName", parameters TO result%
with the following code (requires CALLBACK.BBC version 3.4 or later):
SYS FN_syscalls("FunctionName"), parameters TO !FN_systo(result%)
Note particularly the exclamation mark before **FN_systo**!\\ \\ When using the CALLBACK library you must be careful how you pass **string** parameters. In the event that one or more of the parameters needs to be a string, add a NUL-termination (requires //BBC BASIC for Windows// version 5.93a or later):
parameter$ += CHR$(0) : REM Add NUL termination
SYS FN_syscalls("FunctionName"), parameter$ TO !FN_systo(result%)
In the event that you need to call the API function by //address// rather than by //name// use the following code:
SYS FN_syscalln(FunctionAddress%), parameters TO !FN_systo(result%)
You **must** include the TO clause even if you don't need the value returned by the API function. In that case simply assign the value to a dummy variable.\\ \\ The callback routine (which will sometimes be specified as one of the parameters) should be entered as:
FN_callback(FNfunctionname(), npar%)
Here **FNfunctionname** is the name of the callback function in your program and **npar%** is the number of parameters it takes (this will be specified in the description of the API function).\\ \\ You should ensure that your callback function executes as quickly as possible; ideally it should not perform any input or output.\\ \\ The use of this facility is probably best illustrated by means of a few examples:\\ \\
===== Enumerating windows =====
\\ The following program will count the number of windows and store their handles in an array:
INSTALL @lib$+"CALLBACK"
DIM hwnd%(999)
index% = 0
SYS FN_syscalls("EnumWindows"), FN_callback(FNenumwinfunc(), 2), 0 TO !FN_systo(result%)
PRINT "Exit code = ";result%
PRINT "Number of windows enumerated = ";index%
PRINT "hwnd%(0) = ";hwnd%(0)", hwnd%(";index%-1;") = ";hwnd%(index%-1)
END
DEF FNenumwinfunc(hwnd%, param%)
hwnd%(index%) = hwnd%
index% += 1
IF index% <= 999 THEN = 1 ELSE = 0
===== Enumerating fonts =====
\\ The following program will count the number of fonts and store their names in an array:
INSTALL @lib$+"CALLBACK"
DIM font$(999)
index% = 0
SYS FN_syscalls("EnumFonts"), @memhdc%, 0, FN_callback(FNenumfontfunc(), 4), \
\ 0 TO !FN_systo(result%)
PRINT "Exit code = ";result%
PRINT "Number of fonts enumerated = ";index%
IF index% THEN
PRINT "font$(0) = ";font$(0)
PRINT "font$(";index%-1;") = ";font$(index%-1)
ENDIF
END
DEF FNenumfontfunc(lplf%, lptm%, type%, data%)
font$(index%) = $$(lplf%+28)
index% += 1
IF index% <= 999 THEN = 1 ELSE = 0
===== Enumerating date formats =====
\\ The following program will count the number of available date formats and store them in a string array:
INSTALL @lib$+"CALLBACK"
DIM dfmt$(99)
index% = 0
SYS FN_syscalls("EnumDateFormats"), FN_callback(FNenumdatefunc(), 1), &800, \
\ 1 TO !FN_systo(result%)
PRINT "Exit code = ";result%
PRINT "Number of date formats enumerated = ";index%
FOR i% = 0 TO index%-1
PRINT dfmt$(i%)
NEXT
END
DEF FNenumdatefunc(lpdfs%)
dfmt$(index%) = $$lpdfs%
index% += 1
IF index% <= 99 THEN = 1 ELSE = 0