To conform to the Windows programming conventions, PowerBASIC must provide a "safe" environment for the range of functions that are available. This is achieved by transparently preserving the three volatile registers at the start of each Sub/Function/Method/Property, and restoring these same registers before exit from the procedure. The following example shows approximately how PowerBASIC constructs the entry and exit of a procedure to preserve these registers:
SUB MySub(Params)
! PUSH EBX ' Automatically added by PowerBASIC
! PUSH ESI ' --"---
! PUSH EDI ' --"---
' the actual SUB code is placed here
! POP EDI ' Automatically added by PowerBASIC
! POP ESI ' --"---
! POP EBX ' --"---
END SUB
When writing a procedure in PowerBASIC, we can safely predict that the EBX, ESI, and EDI registers will be automatically saved upon entry and restored upon exit from a procedure.
The virtue of code that observes these conventions is that it allows the programmer to safely assume that a call to any other procedure or API function is certain to follow the same register preservation rules for the EBX, ESI, and EDI registers. This helps ensure that writing Inline Assembler code in PowerBASIC will result in reliable and completely predictable code execution in terms of register use when calling PowerBASIC and API procedures.
The PowerBASIC compiler is also very efficient in the way it calls API system functions. For example, the following BASIC statement which calls the SendMessage API:
CALL SendMessage(hWnd&, %WM_COMMAND, 50, 100)
…is translated into assembly code in the compiled program, to resemble something like this:
PUSH 100
PUSH 50
PUSH %WM_COMMAND
PUSH hWnd&
CALL SendMessage
This direct low level translation is one of the main reasons why PowerBASIC programmers can easily mix API code and assembler code. However, when it comes to intermixing assembler and BASIC code within a procedure, the programmer must take additional care.
See Also
Tricks in preserving registers