=====Passing floating-point values to DLLs===== //by Richard Russell, July 2009//\\ \\ The majority of functions that you are likely to want to call using [[http://www.bbcbasic.co.uk/bbcwin/manual/bbcwin7.html#sys|SYS]] (typically Windows API functions, or functions in third-party DLLs) will require only **integer** or **string** parameters; you can specify those straightforwardly in the **SYS** statement.\\ \\ Occasionally, however, you may need to pass a floating-point parameter to such a function. Unfortunately you cannot usually do that simply by including the appropriate variable or constant in the **SYS** statement; this article describes what you need to do instead.\\ \\ There are two main ways of passing floating-point parameters: **by reference** or **by value**. In the first case you pass a **pointer** to the floating-point value (the memory address at which it is stored), and in the second case you pass the **value** itself. There are also (principally) two different types of floating-point value that the function may require: a 32-bit **float** value or a 64-bit **double** value.\\ \\ You must first ascertain from the documentation of the function whether the parameter is to be passed **by reference** or **by value**, and whether the parameter needs to be a **float** or a **double**; this is vitally important!\\ \\ Below are listed the methods you must adopt in each of the four possible circumstances:\\ \\ ==== 64-bit doubles passed by reference ==== \\ This is the simplest case to deal with in BB4W. Suppose you want to pass the variable **fpv**: fpv# = fpv * 1.0# SYS "FunctionName", ^fpv# Here the value is converted (if necessary) to a 64-bit float (by multiplying it by **1.0#**) and then stored in the 64-bit variable **fpv#**. The parameter supplied in the SYS call is the address of the variable (**^fpv#**).\\ \\ Rather than a scalar value, you may need to pass an **array** of values (arrays are invariably passed by reference). You can do that in a similar way, for example to pass the array **fpv#()**: fpv#() *= 1.0# SYS "FunctionName", ^fpv#(0) Here it is assumed that the array was originally declared with 64-bit elements (i.e. either in ***FLOAT 64** mode or by explicitly specifying a **#** suffix).\\ \\ If your array uses suffices starting at **1** rather than 0 then you will need to pass the address of the base element: fpv#() *= 1.0# SYS "FunctionName", ^fpv#(1) ==== 64-bit doubles passed by value ==== \\ Since each parameter of the **SYS** statement is passed as a 32-bit value, a 64-bit floating-point value must be passed as **two** parameters. Suppose you want to pass the variable **fpv**: SYS "FunctionName", FN_dl(fpv), FN_dh(fpv) The 'helper functions' **FN_dl** and **FN_dh** are listed [[/Passing%20floating-point%20values%20to%20DLLs#helpers|below]]. If you prefer to use 'inline' code rather than call the helper functions you can do that as follows: fpv# = fpv * 1.0# SYS "FunctionName", !^fpv#, !(^fpv#+4) ==== 32-bit floats passed by reference ==== \\ BBC BASIC for Windows doesn't have a native 32-bit float type, so a conversion is required. Suppose you want to pass the variable **fpv** by reference: temp% = FN_f4(fpv) SYS "FunctionName", ^temp% Here the temporary variable **temp%** is loaded with the 32-bit float, and then its address is passed as the parameter.\\ \\ ==== 32-bit floats passed by value ==== \\ This is similar to the previous case, except that the temporary variable is not required. So to pass the variable **fpv** by value: SYS "FunctionName", FN_f4(fpv) The 'helper function' **FN_f4** is listed [[/Passing%20floating-point%20values%20to%20DLLs#helpers|below]].\\ \\ ==== Helper functions ==== \\ Here are the functions used in the above examples: REM Convert to 64-bit double (low 4 bytes) DEF FN_dl(A#) A# *= 1.0# = !^A# REM Convert to 64-bit double (high 4 bytes) DEF FN_dh(A#) A# *= 1.0# = !(^A#+4) REM Convert to 32-bit float DEF FN_f4(a#)LOCALP%:P%=^a#:IFABSa#<1E-38 THEN=FALSE =P%!4 AND NOT&7FFFFFFFOR(P%!4-&38000000<<3 OR!P%>>29 AND7)+(!P%>>28 AND1)