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 [|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: code format="bb4w" INSTALL @lib$+"CALLBACK" code To use the library, replace the conventional method of calling a Windows API function: code format="bb4w" SYS "FunctionName", parameters TO result% code with the following code (requires CALLBACK.BBC version 3.4 or later): code format="bb4w" SYS FN_syscalls("FunctionName"), parameters TO !FN_systo(result%) code 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): code format="bb4w" parameter$ += CHR$(0) : REM Add NUL termination SYS FN_syscalls("FunctionName"), parameter$ TO !FN_systo(result%) code In the event that you need to call the API function by //address// rather than by //name// use the following code: code format="bb4w" SYS FN_syscalln(FunctionAddress%), parameters TO !FN_systo(result%) code 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: code format="bb4w" FN_callback(FNfunctionname, npar%) code 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: code format="bb4w" 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 code

Enumerating fonts
The following program will count the number of fonts and store their names in an array: code format="bb4w" 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 code

Enumerating date formats
The following program will count the number of available date formats and store them in a string array: code format="bb4w" 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 code