✔ Appearance ✔ Standard ✔ Console
"statementLabel" ENTERPROC [(intVar1 [,intVar2 ...])] [statementBlock] EXITPROC [= intVar3]
"statementLabel" ENTERPROC FN fnName[(intVar1 [,intVar2 ...])] [= type] [statementBlock] EXITPROC [= returnValue]
ENTERPROC statement marks the beginning of a procedure block, which must end with an
EXITPROC statement. A procedure block is used to implement a function that uses the Pascal calling convention, which is a certain way that the function manipulates the stack. The most common use for this kind of function is to implement Toolbox "callback" procedures (often called "application-defined routines" in Inside Macintosh). Such callback procedures must use the Pascal calling convention.
ENTERPROC procedure block can only appear within the "main" scope of the program; not within a
LOCAL FN. Each of the
intVar's must be either a short (2-byte) integer variable or a long (4-byte) integer variable, or a
HANDLE variable. The
statementBlock can contain any collection of FB statements except another
EXITPROC block (i.e., procedure blocks cannot be nested). The scope of all the variables referenced in the procedure block is either global (if the variable was declared earlier in a
END GLOBALS block) or local to the procedure block itself.
A procedure block is called when some caller (typically a Toolbox routine) refers to the procedure's address in memory; your program can use the
PROC"statementLabel" function to get that address. Typically, your program would pass that address to the Toolbox routine, to identify the procedure block as a "callback" procedure. When the procedure block is called,
intVar2, etc. are assigned values which are passed by the caller. When the
EXITPROC statement is reached, control is returned back to the caller, and if
returnValue) was specified, its value is returned to the caller.
It's important that you know the number and types of parameters (if any) that the caller expects to pass to your procedure block, and that you set up the
intVar2 (etc.) parameters in the
ENTERPROC statement accordingly. Likewise, you should know whether the caller expects your procedure block to return a value and, if so, whether the caller expects a 2-byte or a 4-byte value. If you use Syntax 1, you should specify a variable of the appropriate size in
intVar3 if the caller expects a return value; otherwise you should omit
intVar3. If you use Syntax 2, you should specify the name of a 2-byte or 4-byte type (such as
POINTER) in the
type parameter, and specify a
returnValue expression of that type, if the caller expects a return value; otherwise, you should omit the
type and the
returnValue. If you do not set up the input parameters and the return parameters correctly in your
EXITPROC statements, then your program is likely to crash when the procedure block is called. See <a href="app.%20c%20data%20types.html">Appendix C</a>: Data Types and Data Representation, for a list of valid 2-byte and 4-byte variable types.
If you use Syntax 2, you can also execute a procedure block by using the
FN <userFunction> statement, although there is generally little reason to do this (it's usually better to use a
LOCAL FN when you want to create a procedure that will be explicitly called by your program).
When your program starts up, it will not automatically "skip over" the lines in a procedure block, the way it skips over the lines in a
LOCAL FN. In order to prevent your procedure block from being executed inadvertently, you should either branch around the procedure block using
GOTO, like this:
GOTO "Detour" "myProc1" ENTERPROC(var&) : EXITPROC "myProc2" ENTERPROC(var1%, var2&) : EXITPROC = result& "Detour"
or you should place the procedure block after an
END statement, like this:
'[main part of program here] END '======= Procedures ======= "myProc1" ENTERPROC(var&) : EXITPROC "myProc2" ENTERPROC(var1%, var2&) : EXITPROC = result&
CALL <address>; Appendix C: Data Types and Data Representation