PROCEDURES
Updated: Apr 16, 2005

Declare, Subroutines & Functions
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Declare statements allow a one-pass compiler to develop a list of user
symbols to process source code and provide information about external
modules such as system and other .dlls and linkable .obj modules. 

For procedures defined in your source code:

  DECLARE SUB | FUNCTION name [(param1 As type[, param2 As type[, etc]])] _
    [As type]

For procedures defined in external .dll or .obj modules:

  DECLARE SUB | FUNCTION name LIB "libname" [ALIAS "aliasname"] _
    [(param1 As type[, param2 As type[, etc]])] [As type]

The syntax above may look complicated, but hold your breath.  Items in [.]
are optional.  DECLARE FUNCTION requires "As <type>".  ALIAS is used only
when LIB is defined and is optional.  "_" continues a statement on the next
line.

Let's start with simple examples:


=====Declare SUB

  Declare SUB MySub
  'code
  Call MySub
  'code

  SUB MySub 'here we define what we do in MySub
  'code
  IF {condition} THEN Exit Sub
  'more code
  END SUB

Above, MySub is declared and defined.  In the SUB code, one can EXIT SUB
at any time.

In the DECLARE statements, type is the variable type.  Please see "Dimension".
The symbols used for param1 to param?? for user-defined SUBs and FUNCTIONs
are dimensioned automatically, as shown in compiler Symbol Table output.


=====Declare FUNCTION

Now a simple FUNCTION example:

  DEFREAL10 x,y,z
  Declare FUNCTION MyFun As LONG  
  'code
  x=100: y=2: z = MyFun 
  'code

  FUNCTION MyFun As LONG
  'MyFun can access dimensioned variables and does not need arguments
  RESULT = -1 'if we want to set a default result
  'code
  IF x > 0 AND y > 0 THEN RESULT = x / y ELSE Exit FUNCTION
  'MyFun returns either -1 or x/y
  'more code
  END FUNCTION

In the FUNCTION code, you can also assign the result to the name of the
function.  Above, MyFun = -1 would be the same as RESULT = -1.  Unlike
some Basic compilers which do not flag missing result statements, absence
of a defined function result as described above is assumed to be a source
code error.

If your SUB or FUNCTION has arguments, you just add them in (... ).


=====Calling Windows API functions (hotapi.bas):

What if the SUB or FUNCTION is not defined in your own code?  API calls are
illustrated in hotapi.bas, and may be as simple as:

  Declare FUNCTION GetLastError LIB "kernel32" ALIAS "GetLastError" () _
    As LONG
  Declare FUNCTION Beep LIB "kernel32" (BYVAL freq As LONG,_
    BYVAL duration As LONG) As LONG

  DIM rval As LONG
  'code which might cause an error condition
  rval=GetLastError  
  rval=Beep(400,2000)

The keyword BYVAL is not necessary and may be omitted.  The LIB is
kernel32.dll and the ALIAS may be defined or omitted.  ALIAS allows you
to refer to the procedure with one name in your code, but HotBasic will
substitute the ALIAS name, if present, at compile time.

If the declared argument is As STRING or As <type>, HotBasic automatically
posts the argument as a pointer.  

The keyword BYREF provokes a Warning and is otherwise ignored.  Indeed, 
it is not needed for STRING or type arguments, since a pointer is used.
For other arguments, use As DWORD as the qualified type and a pointer as the
argument in the call statement (Please see @ and VARPTR in "Numeric
Functions".)


=====Calling Procedures in a Non-Windows .DLL (hotcall.bas and hotdll.dll):

hotcall.bas shows that a HotBasic executable can use funtions in a .DLL
compiled by HotBasic or obtained elsewhere.  The required Declare statements
are identical in form.  HotBasic provides two run-time errors:
(1) LIB .dll file not found and (2) function name not found in LIB .dll.


=====Calling Procedures in .OBJ Modules (hotlink.bas and hotobj.obj):

How do we link an .obj module compiled by HotBasic or obtained elsewhere?
For each procedure in the external module, we have a DECLARE like above with
one crucial difference: the full name of the file is specified.

  Declare SUB DoNeatThing LIB "neatthings.obj" [(args)] 
  'code
  DoNeatThing[(args)] 'or Call DoNeatThing[(args)] calls the subroutine.

or use a Declare FUNCTION as above, but with LIB "neathings.obj".  The
.obj file is included in the executable produced.

Please see $INCLUDE in "Directives" (h_direct) on inluding and linking
third-party object modules in compatible .lib library files.

If the SUB has arguments, you may use (..) or not, but no space before (.

  DoNeatThing(MyValue1, MyValue2, etc)
  'or DoNeatThing MyValue1, MyValue2, etc

Note: If the external module is not stdcall (Windows compatible), then do not
include any arguments in the Declare statements and use PUSH to place the
arguments on the stack in the correct order before calling the SUB or FUNCTION.
Please see "Statements > Advanced Techniques".

Another issue is stack clean-up.  For some C language .obj modules, the stack
is not "cleaned up" and you will have to manually POP all the arguments
after return from each call.

For procedures in DLL and OBJ $APPTYPE's or for certain callback procedures
in your main program, the STD keyword may be used and HotBasic will manage
argument retreival from the stack.  STD is positioned where LIB would otherwise
appear in a DECLARE statement -- after the procedure name and before any
arguments.

All DECLARE statements for STD procedures will have arguments equivalent to
4-byte values, exactly as in Microsoft API function definitions.  That is,
a STRING or TYPE is always a pointer (DWORD), numbers are always INTEGER,
DWORD, etc.  When the procedure is called, a BYTE or WORD value may be used
as an argument, but the DECLARE must specify only 4-byte values as arguments.
What happens is that HotBasic posts a BYTE or WORD value as a 4-byte value
when the procedure is called.

STD can be used for callback procedures.  Example:

  DECLARE FUNCTION MyWndProc STD (hwin as DWORD, _
    pmsg as DWORD, wpar as DWORD, lpar as DWORD)


=====GOSUB

With GOSUB, no Declare is needed (please see hottips.html) and any LABEL may
start, or be an alternate entry point into, a subroutine.

  GOSUB ThisSub: GOSUB ThatSub
  'code

  ThisSub:  'this is just a LABEL
  'code
  RETURN

  ThatSub:
  'code
  ThatSubEntry2:
  'code
  RETURN
  
After all source code is processed, HotBasic checks if GOTO and GOSUB LABELS
exist.

A line LABEL may help describe what a SUB does:  GOSUB ComputeIncome.
But it could be an integer number, too, as in older versions of Basic
(example in hottest.bas).


+ Penthouse (registered) version

Copyright 2003-2005 James J Keene PhD
Original Publication: Oct 8, 2003
