The following built-in functions deal with add-on functions contained in Dynamic Link Libraries (ie, DLL files).

CONVERTDATA Convert some binary datatype to REXX variables, or vice versa.
FUNCDEF Make an external function (in a DLL not normally callable by REXX) available to be called.
QUERYMACRO Tests if a script or macro DLL is already loaded into the macro table.
RXFUNCADD Make an external function (in a DLL written for REXX) available to be called.
RXFUNCDROP Make an external function no longer available.
RXFUNCQUERY Check if an external function is available to be called. Get the version of a DLL/EXE. Check if there are function name conflicts.
RXFUNCERRMSG Fetch an error message for the last error of RXFUNCADD() or FUNCDEF().


FUNCDEF

Registers a function in a DLL that is not designed to directly support REXX. After such a function is registered (once), then a script may directly call it as many times as desired.

Synopsis

err = FUNCDEF(REXXname, Definition, DLLname, FUNCTIONname, Errors, CallType)

Args

REXXname is the desired name that you would like to use when you call the function in your script. The name you use to call the function does not need to be the same as the real name of the function. REXXname is automatically uppercased. Be sure to enclose the name in quotes if you're directly supplying it to FUNCDEF().

DLLname is the name of the DLL that contains the function. You do not need to put any .dll extension upon the name, although you may optionally do so for some operating systems. Upon some operating systems, DLLname may be case-sensitive. (ie, A DLL name of "Blort" is not the same as "blort"). If you know exactly where the DLL is located upon the system, you can supply the full pathname (ie, 'C:\MyDir\Blort"). Otherwise, the DLL must be located in a place where the operating system can find it. Be sure to enclose the name in quotes if you're directly supplying it to FUNCDEF().

Definition is a string containing numerous items of information, each separated by a comma. The first item is the type of return from the function. It must be one of the types listed below, or blank if the function does not return a value. The next item is the type for the first argument passed to the function (if there is such an argument). What follows will be the types for the remaining arguments (if any more). Consult the programming documentation with the DLL to determine how many args it accepts (if any), what it returns if anything, and the type of those args/return. (Warning: Your script may crash, or perform other unexpected/dangerous behavior, if you specify the wrong number/type of args/return).

FUNCTIONname is the real name of the function. Upon some operating systems, this may be case-sensitive. (ie, A function name of "Blort" is not the same as "blort"). Be sure to enclose the name in quotes if you're directly supplying it to FUNCDEF(). If omitted, then FUNCTIONname is the same as REXXname except that the case of REXXname is used as-is.

Errors is as described in Calling a non-REXX function.

CallType is the method used to pass arguments to the function, as so:

Value Meaning
api Args pushed on stack in C order, cleanup done by called function. Most Windows operating system functions use this calltype.
c Args pushed on stack in C order, cleanup done by REXX.
pascal Args pushed on stack in pascal order, cleanup done by called function.
pc Args pushed on stack in pascal order, cleanup done by REXX.

If omitted, 'api' is assumed. Consult the programming documentation with the DLL to determine what call type its function uses. (Warning: Your script may crash, or perform other unexpected/dangerous behavior, if you specify the wrong call type).

Returns

0 if the function is successfully made available to be called. If an error, a non-zero value is returned as so:

Value Meaning
10 There is already a function registered with REXXname. You cannot use the same REXXname for more than 1 function. Each must have a unique REXXname.
40 The DLLname you provided can't be found/loaded. Check the spelling you used. Upon some operating systems, letters may be case-sensitive. Also check that the DLL is located where the operating system can find it easily. If necessary, include the full path on the DLL name.
50 The FUNCTIONname you provided doesn't actually exist in the DLL. Check the spelling you used. Remember that letters are case-sensitive.

Notes

If one of the above error occurs, the RXFUNCERRMSG() built-in will return an error message describing a detailed reason for the error. Reginald also raises a FAILURE condition. CONDITION('E') will return an error/sub-error number of 81.xx where xx is one of the error values shown above.

If there is a memory allocation error, or an error in the way that you've specified your Definition string, or you passed bad arguments to FUNCDEF, then SYNTAX will be raised instead of FAILURE. If you specified a bad data type in some Definition string, then CONDITION('E') will return an error/sub-error number of 35.1. If you referenced the name of some struct, but forget to initialize its respective variable with its Definition string, then you'll get an error/sub-error of 16.2. CONDITION('D') will give an informative error message.

For every function that you FUNCDEF(), it's recommended that you also RXFUNCDROP() that function when you no longer need to make any further calls to it. This can save some memory and may increase speed execution of your script.

If DLLname is omitted, then FUNCDEF() can be used to register a struct (without also registering a function). In that case, REXXname is simply the struct's name (without the word 'struct' preceding it), and Definition is the definition string for that struct. (You do not need to set a similiarly-named variable with the definition string. But if the struct references other structs, then you will need to setup variables with Definition strings for them, unless those other structs have already been registered, either separately, or along with a function).

The Definition string contains numerous items of information, each separated by a comma. Here is the synopsis of the Definition string:

return_type , arg1_type , arg2_type , etc...

Types of arguments/returns:

Value Meaning
'8' An 8-bit (char) whole number.
'16' A 16-bit (short) whole number.
'32' A 32-bit (long) whole number.
'8u' An unsigned 8-bit (unsigned char) whole number.
'16u' An unsigned 16-bit (unsigned short) whole number.
'32u' An unsigned 32-bit (unsigned long) whole number. A returned (ie, from the function) pointer or handle to something that your REXX script is not supposed to directly manipulate would be declared as this type.
'8[X]' Pointer to an array of 8-bit (char) whole numbers. X is the number of items in the array.
'16[X]' Pointer to an array of 16-bit (short) whole numbers. X is the number of items in the array.
'32[X]' Pointer to an array of 32-bit (long) whole numbers. X is the number of items in the array.
'8u[X]' Pointer to an array of unsigned 8-bit (unsigned char) whole numbers. X is the number of items in the array.
'16u[X]' Pointer to an array of unsigned 16-bit (unsigned short) whole numbers. X is the number of items in the array.
'32u[X]' Pointer to an array of unsigned 32-bit (unsigned long) whole numbers. X is the number of items in the array.
'char' A single (8-bit) ascii character.
'char[X]' Pointer to an array of ascii characters. X is the number of characters in the array.
'str[X]' Pointer to an array of nul-terminated ascii characters (ie, a C-style string). X is the minimum number of characters in the array. If X is omitted, then the array is however many characters it is initialized to be.
'struct name' A 'structure' where name is the name of the REXX variable that defines the type of each field in that struct. The value of that variable is just like the definition string above, except that there is no return type first. There are only the type for each field, each separated by a comma.
'struct name[X]' Pointer to an array of 'structure' where name is the name of the REXX variable that defines the type of each field in that struct. X is the number of structures in the array.
'func name' Pointer to a callback (ie, some subroutine in your script that is called by a non-REXX-function) where name is the name of the variable that contains the Definition string for your subroutine.

The 'func' type is applicable only to an argument passed to a function or some field of a structure. It can't be specified as a return.

'void' As the return type, 'void' means that the function is returning a handle (ie, a special numeric value) to some array or struct that your script does not intend to directly access. For an argument passed to a function, or a field of a struct, 'void' indicates one of these handles (ie, special numeric value) that was returned by some function.

If a function doesn't return a value, then place nothing before the first comma.

For a return type that is an array (ie, [] is used) or a struct, and an illegal address is returned by the function, then SYNTAX condition is set (with error number 44) and no other REXX variables associated with that return are set.

For an argument that is a pointer type (ie, [] or pointer qualifier is used) or a struct, and you expect the function to fill in that array/struct with values to be returned to your script (in some REXX variable you specify), then you should append 'stor' to the argument's type. For example, if you are passing an array of four, 32-bit numbers to a function, which the function is going to fill in, then you would declare that argument's type as '32[4] stor'.

When calling the function that you've registered, REXX converts the args that you pass to the function to their appropriate data types (as you specified in the Definition string). For the function's return value, it is converted and stored in the REXX variable to which you assign the return. For an array or struct, the values will be stored in REXX compound variables.

See Calling a non-REXX function for more information and examples about how to call the function.

Examples

Example use Return value
FUNCDEF('Blort', 'mydll', ', 32')
 0 /* If successfully adds 'Blort' in DLL 'mydll' to be
 called as BLORT(). It takes one 32-bit numeric argument,
 and returns no value. */


CONVERTDATA

Converts some non-REXX (ie, typically C) datatype into a REXX variable(s), or vice versa. Used mostly in a REXX subroutine that is a callback (ie, used with a FUNCDEF defined DLL function), or a REXX GUI event handler.

Synopsis

Address = CONVERTDATA(Address, Variable, Definition, Operation)

Args

Address is the pointer to (ie, base address of) whatever non-REXX datatype needs to be converted. For example if there is an array at address 00000100 hex, then this is the numeric string "256".

Variable is the name of the REXX variable where the data is converted. If converting a C struct or array, then this may be the name of a stem variable whose tails are set to various fields of the struct/array. Remember to place quotes around the variable name and make it uppercase if necessary.

Definition is the definition string for the conversion. It is specified like FUNCDEF's definition string, except only one datatype can be specified. For example, to convert an array of 10 32-bit numbers, the definition string would be "32u[10]". If omitted, it defaults to "void".

Operation is one of the following:

Operation Meaning
'FROM' Convert the REXX variable to the binary datatype at the specified 'Address'.
'TO' Convert the binary datatype at the specified 'Address' to the REXX variable.
'A' Allocate some datatype which will be automatically freed by REXX when the level (that set the MEMPOINT OPTION) ends. 'Address' is the address at which to store the datatype, or 0 if not linking this to some other datatype field. If 'Variable' is not "", it is a field offset from "Address". (Valid only with a struct datatype). The Definition string determines how many bytes to allocate. If Definition string is omitted, then Variable is simply the number of bytes to allocate.
'A0' Same as 'A', except the memory is zeroed.
'OFFSET' Get the offset to some field of a struct or the size of the struct. "Address" is the field number, or 0 to get the size of the struct.
'=' Assign some datatype allocated with 'A' to the specified REXX Variable. "Address" is the value that CONVERTDATA returned when the datatype was allocated. If Definition is specified, it is the length of the data. (Cannot be larger than the original allocation). It is removed from the free list. If "Variable" is not supplied, then the datatype is freed.

If Operation is omitted, it defaults to 'TO'.

Returns

The base address of the binary datatype, otherwise an empty string if an error.

Notes

SYNTAX condition is raised for an illegal Definition String (error number 35.1), or memory allocation error (5), or the wrong number of arguments are passed to this function (40.3 or 40.4) or required args are omitted (40.5), or 'Address' is not a numeric string or a field that is supposed to be numeric has been assigned a non-numeric value (40.12), or the Definition string is for a func type referencing a subroutine that cannot be found in the script (16.1) or a struct whose Definition string can't be found (16.2).

If you trap NOVALUE condition, then when you are doing a 'FROM' operation and have forgotten to set the value of some REXX variable, NOVALUE is raised.

If you aren't trapping NOVALUE when doing a 'FROM' operation, and have forgotten to set the value of some REXX variable, then SYNTAX may be raised for numeric (and void) types, or in the case of a str/char data type, the value stored will be an empty string. If the field is a pointer in a struct, a nul pointer is stored instead.

If Address is 0 for a 'FROM' or 'TO' operation, then an empty string is returned without any conversion performed.

If 'stor' is specified on the Definition string, then CONVERTDATA allocates the memory for the binary datatype and returns the base address of it. In that case, the 'Address' passed to CONVERTDATA is assumed to be a handle where to store that memory address, or 0 if the memory address is not to be stored. 'stor' is applicable only with a "FROM" Operation. Memory allocated by CONVERTDATA is automatically freed when your script ends. This provides a convenient means of allocating memory that must be passed to some FUNCDEF'ed function, but which your script is expected to free at some point. Even if your script abruptly terminates (perhaps with a SYNTAX error), the memory will be freed. (The same is not true if you use some operating system function to allocate memory). Do not use this if the FUNCDEF'ed function will be freeing the memory (ie, use an operating system function instead to get memory).

Examples

Assume that the following struct named MYSTRUCT is FUNCDEF'ed:

FUNCDEF('MYSTRUCT', 'str *, 32')
Now you wish to initialize some REXX stem variable named MyVar to some values, allocate memory and convert it into a binary struct, and get the address of that allocated memory.
/* Initialize MyStruct */
MyVar.1 = "Some string"
MyVar.2 = -1

/* Allocate memory and convert to a binary datatype */
address = CONVERTDATA(, 'MYVAR', 'struct MYSTRUCT', 'FROM')

/* Check for success */
IF address \== "" THEN SAY "address is now the base address of this binary datatype."

See also

FUNCDEF


QUERYMACRO

Checks if a script with a given name is already loaded into the Macro table (for example, if it is a script inside of a loaded Macro DLL). Can also check if an object script is loaded (ie, being used by some object).

Synopsis

result = QUERYMACRO(MACROname)

Args

MACROname is the name of the script to check. This can be a script name with a full path (such as "C:\MyDir\Blort.rex").

Returns

0 if the script is not in the macro table, 1 if it exists in the "before" macro table with the full name, 2 if it's in the "before" table with a short name, 3 if it's in the "after" table with the full name, 4 if it's in the after table with a short name.

Notes

Two macros can't have the same script name. So, if you attempt to load the same Macro DLL twice, you'll get an "Already exists" error the second time. QUERYMACRO can be used to check if a Macro DLL has already been loaded, by querying for the name of one of the scripts that you know to be inside of that Macro DLL.

A "full name" is the script name with its path. A "short name" is just the script name without its path. Some macros (such as those in Macro DLLs) have only short names. But even when you specify a full name, if there is a macro with the same short name, then QUERYMACRO will match it.

Reginald maintains two macro tables, a "before" and "after" table. Macros in the "before" table supercede those on disk. Macros in the "after" table do not. For example, assume you make the following call in your script:

Blort.rex()
If there is macro named Blort.rex in the "before" table, it will be used instead of any script on disk named "Blort.rex". On the other hand, even if there is macro named Blort.rex in the "after" table, it will not be used unless there is no macro named Blort.rex in the "Before" table, nor such a script on disk.

Scripts inside of Macro DLLs get added to the "Before" table.

Examples

Example use Return value
QUERYMACRO('BLORT.REX')
 0 /* If the script named BLORT.REX isn't in the macro table */

See also

RXFUNCADD


RXFUNCADD

Makes an external (add-on) DLL function available to be called. This is implemented only in the full version of Reginald (not Reginald Lite) and is used to load and register a function in some legacy REXX add-on DLL.

Synopsis

result = RXFUNCADD(REXXname, DLLname, FUNCTIONname)

Args

REXXname is the desired name that you would like to use when you call the add-on function in your script. The name you choose for the add-on function does not need to be the same as the real name of that function. It can be any name that you desire, as long as you haven't already used that name for some other add-on function. It is recommended that you use all upper-case for this name. Be sure to enclose the name in quotes if you're directly supplying it to RXFUNCADD().

DLLname is the filename of the DLL that contains the function. You do not need to put any .dll extension upon the name, although you may optionally do so for some operating systems. Upon some operating systems, DLLname may be case-sensitive. (ie, A DLL name of "Blort" is not the same as "blort"). If you know exactly where the DLL is located upon the system, you can supply the full pathname (ie, 'C:\MyDir\Blort"). Otherwise, the DLL must be located in a place where the operating system can find it. Be sure to enclose the name in quotes if you're directly supplying it to RXFUNCADD().

FUNCTIONname is the real name of the function. Upon some operating systems, this may be case-sensitive. (ie, A function name of "Blort" is not the same as "blort"). Be sure to enclose the name in quotes if you're directly supplying it to RXFUNCADD(). If omitted, then REXXname is used as the real name of the function.

Returns

0 if the function is successfully made available to be called. If an error, a non-zero value is returned as so:

Value Meaning
10 There is already a function registered with REXXname. You can't use the same REXXname for more than 1 function. Each must have a unique REXXname.
40 The DLLname you provided can't be found/loaded. Check the spelling you used. Upon some operating systems, letters may be case-sensitive. Also check that the DLL is located where the operating system can find it easily. If necessary, include the full path on the DLL name.
50 The FUNCTIONname you provided doesn't actually exist in the DLL. Check the spelling you used. Remember that letters are case-sensitive.

Notes

Before you can call a function in a DLL, it must be made available to be called either by calling RXFUNCADD(), or sometimes, a DLL will register some or all of its own functions thus bypassing the need for you to call RXFUNCADD() upon each function in that DLL you wish to call. See DLL Functions for more details.

If one of the above errors occur, the RXFUNCERRMSG() built-in will return an error message describing a detailed reason for the error. Reginald also raises a FAILURE condition and CONDITION('E') will return an error/sub-error number of 81.xx where xx is one of the error values shown above.

If there is a memory allocation error, or you passed bad arguments to RXFUNCADD, then SYNTAX will be raised instead of FAILURE. CONDITION('D') will give an informative error message, and CONDITION('E') will give you the error/sub-error number.

Examples

Example use Return value
RXFUNCADD('BLORT', 'mydll', 'myfunction')
 0 /* If successfully adds 'myfunction' in DLL 'mydll'
 to be called as BLORT() */


RXFUNCDROP

Makes an external function no longer available. Can also deregister a struct registered via FUNCDEF().

Synopsis

result = RXFUNCDROP(REXXname, type)

Args

REXXname is the name that you used when you RXFUNCADD'ed this function.

type is supplied only if you wish to deregister a struct that was registered with Reginald's FUNCDEF, or a REXX subroutine that was registered as a callback. To deregister a struct, type = 1, and REXXname is the struct name. To deregister a callback, type = 2, and REXXname is the REXX subroutine name.

Returns

0 if the function is successfully dropped. If an error, a non-zero value is returned as so:

Value Meaning
30 The function was not registered. (It may already have been dropped).

Notes

It is generally safe to attempt to drop a function that has not been RXFUNCADD'ed, or a function that has already been RXFUNCDROP'ed. But RXFUNCQUERY can be called first to see if a function is already available before attempting to drop it.

Examples

Example use Return value
RXFUNCDROP('BLORT')
 0 /* If successfully drops a function called as BLORT() */

See also

RXFUNCADD


RXFUNCQUERY

Checks if an external function is available to be called. Can also check the version of an executable or DLL. Also, can check if there are any conflicts between add-on function names and your script's label names.

Synopsis

result = RXFUNCQUERY(REXXname, Option)

Args

REXXname is the name that you used when you RXFUNCADD'ed this function. If omitted, then RXFUNCQUERY checks for any conflicts with function names.

options may be one of the following:

Option Meaning
'V' Get version information. REXXname is the name of the file. (It may include the full path).

If you call RXFUNCQUERY without any args, then it will check if any labels in your script have the same names as any add-on DLLs you have RXFUNCADD'ed. If so, then SYNTAX condition will be raised.

Returns

0 if the function is currently available. Otherwise, a non-zero value is returned as so:

Value Meaning
30 The function is in the process of being registered, or has been dropped.
40 The function is not registered.

Examples

Example use Return value
RXFUNCQUERY('BLORT')
 0 /* If the BLORT() function is available to be called */
RXFUNCQUERY()
 0 /* If no conflicts with add-on function names and labels */
RXFUNCQUERY('rexxgui', 'V')
/* Returns the version of rexxgui.dll */

See also

RXFUNCADD


RXFUNCERRMSG

Fetch an error message for the last error of RXFUNCADD().

Synopsis

message = RXFUNCERRMSG()

Args

None.

Returns

An error message associated with a preceding call for RXFUNCADD(), or an empty string if there was no error.

Notes

This error message is gotten from the operating system, so it specifically identifies the reason why a call to RXFUNCADD() or a LIBRARY statement failed. The exact wording of the error message will vary on different operating systems.

See also

RXFUNCADD