=====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