StdCall(), LStdCall() Functions

Purpose

Executes a subroutine at a specified address and returns a Long or Large value.

Syntax

dw = StdCall(addr)([parameters])
lg = LStdCall(addr)([parameters])

dw: Long
lg: Large
addr: iexp
parameters: aexp

Description

Both functions are used to call a procedure (not a function) using its address (enclosed in the first set of brackets and which can be derived with ProcAddr) and send the required parameters (enclosed in the second pair of brackets in the order they are expected by the called routine). This is useful in a number of situations, examples being a block of machine/assembly code stored inline or when you wish to call a routine in the main program from a library.

The parameters are 32-bit integers by default but can be coerced to a specific format by preceding the value with one of the following designators:

CurCurrencyDbl DoubleInt Integer
L LongLarge Large integerSng Float, Single
Var VariantW Word/16-bit Integer

In addition, you can send strings, types and arrays of all types ByRef (only) by passing the address (* Operator) of the object as one of the parameters. Passing OCX controls is also possible by passing the handle and reconstructing it in the called procedure using Ocx(); similarly, pictures can be passed by hBmp and recreated with CreatePicture.

NOTE: There is currently no known way of passing a Byte variable/value to the stack.

If you wish to get a return value - as in a Function - then this should be added to the eax register for StdCall and eax:edx for LStdCall as in the example below.

Example

Trace StdCall(ProcAddr(test1))( Large:2, 3 )

Trace LStdCall(ProcAddr(test2))( Large:6, 4 )

Debug.Show

 

Procedure test1(la As Large, i%)

Trace la

Trace i%

i% = la * i%

. mov eax, i%

EndProc

 

Procedure test2(la As Large, i%)

Local hl%, ll%

Trace la

Trace i%

la = i% * la

hl% = HiLarge(la) : ll% = LoLarge(la)

. mov eax, ll%

. mov edx, hl%

EndProc

Remarks

A Procedure takes it parameters by value using the StdCall convention. StdCall is the default calling convention for GFA-BASIC 32 and Windows.

If you are calling assembly or C code, [L]StdCall()() expects the subroutine to clear the stack - this is done by ending the code with 'ret xx' where xx is the memory size of all the parameters passed; however, if you are calling a GFABASIC procedure, this is not necessary and will, in fact, cause an error.

The parameters (when 4 bytes in size) are placed onto the stack as follows:

a% = StdCall(addr%)(1, 2, 3)

12[esp] 3
8[esp] 2
4[esp] 1
[esp] return address

If the called code is assembly or C, it should be terminated with 'ret 12'.

Known Issues

  1. If you are using early versions of GFABASIC than 2.36, sending more than the first parameter as anything but a 32-bit integer causes an error.
    [Reported by Sjouke Hamstra, 22/07/2019]
  2. For an unknown reason, calls made by StdCall can fail in a compiled program with error '53 Stackpointer at PasCall', whether that be an executable, library or .gll.

    The only workaround is to replace StdCall with assembly code, as explained by Sjouke below:

    "The heart of StdCall is nothing more than – in assembler –
    . mov eax, address
    . call eax

    "Besides this, StdCall puts the parameters on the stack, saves the state of the CPU, and calls the function at the passed address. Before returning it restores the state of the CPU and StdCall checks the stack pointer, it must be the same as before invoking the function. That is where the error occurs, somehow the stack is corrupted, or GB thinks so."
    [Reported by Sjouke Hamstra, 22/07/2019]

See Also

C:(), LC:(), P:(), LP:(), Call(), CallX(), CCall(), LCCall(), PasCall(), LPasCall()

{Created by Sjouke Hamstra; Last updated: 03/09/2021 by James Gaite; Other Contributors: Jean-Marie Melanson}