ADVANCED TECHNIQUES Updated: Feb 14, 2009 ARRAYREF + ARRAYREF$ + Similar to the BYREF statement described below, ARRAYREF() and ARRAYREF$() statements assign values to array elements based on a pointer to the array object and the subscripts. E.g., ARRAYREF(Aptr, i, j) = x 'write numeric value ARRAYREF$(Bptr, i, j) = s$ 'write string value where Aptr and Bptr are pointers to numeric and string arrays respectively, and i and j are the subscripts of the array element. The pointers to a dimensioned array are obtained with the OBJPTR() Numeric Function (please see Numeric Functions). The number of subscripts typically agrees with the number used in the DIM or REDIM statements for a paticular destination array. Please see the ARRAYREF Numeric Function and ARRAYREF$ String Function. These statements and functions providing read/write access to arrays based on array object pointers, facilitate writing of procedures using arrays, which may work with any array, as described by arguments such as the pointer, number and range of subscripts, string vs numeric type, etc. The ARRAYREF family of HotBasic keywords support all array variable types except VARIANT. ASM + statement Inserts assembler language statement directly into your executable. Dim MyVar As Long ASM mov MyVar,1: ASM shl MyVar,5 PRINT MyVar '=32 ASM mov MyVar,esp PRINT "Stack pointer is "; HEX$(MyVar) ASM mov ebx, esp ;get stack pointer ASM mov eax,[ebx+4] ;get stack value ASM mov MyVar,eax PRINT "Stack contains "; HEX$(MyVar) Note: Assembler code can use any CPU registers but must preserve esp. Assembler code may reference any variables dimensioned in the main HotBasic code. Assembler code may create new labels, variables and procedures, but these will be "unknown" (not in Symbol Table) to the HotBasic source code. Assembler code may be inserted in any $APPTYPE. ASM is convenient to insert one or more assembler statements. BEGIN/END ASM is convenient for long assembler code insertions. Assembler code must be compatible with Microsoft assembler language. Please see Appendix > ASM inserts for more details. BEGIN ASM + ;pure assembler code only END ASM BEGIN RUNONCE + 'code which is run only once in an application EXIT RUNONCE 'an optional exit from the run-once code block 'optional additional code END RUNONCE The BEGIN RUNONCE, END RUNONCE and EXIT RUNONCE Statements define a code block which is only run once in an application. An important use in SUB/FUNCTION procedures is to prevent repeated execution of code with repeated calls to the procedure; the code is run once, enhancing procedure performance. The following types of statements generate executable code and therefore should be in a RUNONCE code block: 1. DECLARE ... LIB "xyz" where "xyz" is a .dll file. 2. DEFSTR or DIM t as STRING; these set up the string buffer which need be done only once in an app. An exception might be a procedure that wants to ensure that the string is set to NULL upon procedure entry. [DIM of other variable types does not generate executable code.] 3. DIM of any array, e.g., DIM a(9) as LONG [Use the INITARRAY statement outside a RUNONCE block if you want the array set to all zeros at every entry instance for the procedure.] 4. DIM/CREATE of any BITMAP, FORM and MENU objects. 5. Generally, anything you want to run once. A RUNONCE code block would most frequently be found in procedures where the above kinds of statements are found. E.g., a procedure in an .obj or .dll module that itself declares and calls other .dll modules. BYREF + statement stores a value at the location specified by its address. BYREF(address) = value Please see the related BYREF Numeric Function BYREF$ + statement stores a string in a fixed-length ("static") buffer. BYREF$(address, max_bytes) = string where address points to the destination buffer of size max_bytes. The source string is truncated if necessary to fit in the destination. CALLFUNC pointer, param_n, ..., param_2, param_1 The *last* parameter is listed *first*. pointer must be dimensioned variable = CODEPTR(label) or CODEPTR(sub) DEFDWORD MyProcAddr, FirstParam, LastParam, RetAddr, FirstArg, LastArg MyProcAddr = CODEPTR(MyProc) 'FirstParam is last pushed on to the stack below CALLFUNC MyProcAddr, LastParam, FirstParam 'code END MyProc: POP RetAddr: POP FirstArg: POP LastArg: PUSH RetAddr 'now stack is OK 'code RETURN MyProc above is a LABEL/RETURN procedure without DECLARE. Its code manages argument retrieval from the stack and stack cleanup. Another example: CALLFUNC WinProcAddr, lParam, wParam, uMsg, hWnd 'hWnd is *first* argument. EXTERNAL symbol_1[, symbol_2, ... symbol_n] Used with multiple .obj modules each containing an EXTERNAL statement, where the 4-byte value or address is defined with DIM in only one module. Thus, more than one module can access the same user symbol. EXTERNAL i, j, k 'placed in each linked .obj module DEFINT i, j, k 'defined in only one .obj module FUNCCALL pointer, param_1, param_2,..., param_n Same as CALLFUNC, except for order of parameters. MEMCPY addr1, addr2, nbytes where addr1 is destination, addr2 is source and nbytes is number of bytes to copy; all arguments are non-float values. MEMCPY(@M1, @M2, 8) 'or with () omitted MEMCOPY @M1, @M2, 8 MEMSET addr, byte, count; where byte and count are integer values. MEMSET(@M,46,80) 'fills M with 80 dot (ASCII 46) characters. Caution: Improper use of MEMCPY or MEMSET will likely cause fatal error. POP MyVar; pops application stack to MyVar; e.g., POP i: POP j PUSH MyVar; pushes value of MyVar on to application stack. Caution: Improper use of POP and PUSH will likely cause fatal error. REDIMEX lpFormArray, first_new, last_new where lpFormArray points to a FORM Object array (e.g., @MyButtons), and first_new and last_new is the range of new objects after REDIM. Used after a REDIM which increases the number FORM Objects in array. REDIMEX (+) initializes the newly created FORM Objects. DIM MyButtons(1 to 5) as BUTTON REDIM MyButtons(1 to 10) REDIMEX @MyButtons,6,10 RETVAL integer; sets SUB/FUNCTION return value; e.g., RETVAL MyVar Used to set return value in CallBack procedures, .obj and .dll modules. Use RESULT = in user-defined FUNCTIONs called from the user program. SETGTK handle, string property descriptor, numeric value Linux GTK-mode only; uses g_object_set to assign the "numeric value" to the "property" of the object identified by its "handle". Examples: SETGTK(myEdit,"text",@"HotBasic rocks") SETGTK(myEdit,"editable",false) SYSCALL integer, variable number of arguments Linux only; does kernel syscall where integer is the syscall identifier, followed by the number of arguments required by the prototype for the syscall. Example: SYSCALL 4, 1, @"hello", 5 'print hello to StdOut where 4 is write, 1 is StdOut, with the string pointer and length. WINDOW + statement implements FORM object property assignments or methods by object handle. WINDOW(handle).Left = 10 'set property WINDOW(handle).Repaint 'do method Syntax: WINDOW(handle[,qualified_type]).member The optional qualified_type argument is needed in special cases where the compiler needs this information to generate special code in your application. If handle alone does not work, add the qualified type: WINDOW(handle, TRACKBAR).color = 255 'red Similar WINDOW syntax applies to WINDOW in String and Numeric Funtions. + Penthouse (registered) version Copyright 2003-2009 James J Keene PhD Original Publication: Oct 8, 2003