Defines a run-time parameter in an ABL procedure (internal or external), Windows dynamic link library (DLL) routine, UNIX shared library routine, or ActiveX control event procedure.
Each parameter requires its own DEFINE statement. The parameters must be specified in the RUN statement in the same order they are defined with DEFINE statements. In addition, the parameter types (INPUT, OUTPUT, INPUT-OUTPUT, RETURN, TABLE, TABLE-HANDLE, DATASET, DATASET-HANDLE, and BUFFER) specified in the DEFINE and RUN statements must agree. The corresponding data types and run-time values must also be compatible enough to allow the AVM to perform any necessary conversions.
DEFINE { INPUT | OUTPUT | INPUT-OUTPUT | RETURN } PARAMETER parameter {{ AS [ HANDLE TO ]primitive-type-name | AS [ CLASS ]{object-type-name} | LIKE field }[ EXTENT [constant]]} [[ NOT ] CASE-SENSITIVE ] [ FORMAT string] [ DECIMALS n] [ INITIAL { constant |{[constant[ , constant]...]}}] [ COLUMN-LABEL label] [ LABEL string] [ NO-UNDO ] |
DEFINE { INPUT | OUTPUT | INPUT-OUTPUT } PARAMETER { TABLE FOR temp-table-name[ APPEND ][ BIND ][ BY-VALUE ] | TABLE-HANDLE temp-table-handle[ BIND ][ BY-VALUE ] | DATASET FOR dataset-name[ APPEND ][ BIND ][ BY-VALUE ] | DATASET-HANDLE dataset-handle [ BIND ][ BY-VALUE ] } |
For ABL procedures, primitive-type-name can specify any built-in primitive type used to define variables. For more information on the available primitive types, see the Data types reference entry. For more information on defining primitive type variables, see the DEFINE VARIABLE statement reference entry.
For DLL or UNIX shared library routines, primitive-type-name can specify an ABL DLL data type. ABL DLL data types include the built-in ABL data types CHARACTER and MEMPTR, Windows DLL-equivalent data types, and UNIX shared library data types.
The following table shows how Windows DLL and UNIX shared library data types map to ABL DLL data types.
Example C data type | ABL DLL parameter data type | Windows DLL and UNIX shared library data type |
---|---|---|
char | BYTE | 8-bit unsigned integer |
short | SHORT | 16-bit signed integer |
unsigned
short int |
UNSIGNED-SHORT | 16-bit unsigned integer |
long (32-bit UNIX,
Win32) int1 |
LONG2 | 32-bit signed integer |
unsigned int | UNSIGNED-LONG | 32-bit unsigned integer |
__int64 (Win32) long long (UNIX 32-bit) long (UNIX 64-bit) |
INT64 | 64-bit signed integer |
float | FLOAT | 4-byte floating point |
double | DOUBLE | 8-byte floating point |
char* | CHARACTER | Address (usually 32 bits) |
c-data-type3 | HANDLE
TO parameter-data-type3 |
Address (usually 32 bits) |
char*, output-pointer (which can be char**, short**, and so on), or a pointer to a structure. | MEMPTR | Address (usually 32 bits) |
To indicate that the DLL or UNIX shared library parameter is a pointer to a value rather than the value itself, use the HANDLE TO option. The HANDLE TO option is required when the DLL routine expects a pointer to the value. Note that the CHARACTER data type implies the HANDLE TO option, whether or not you specify it.
For ActiveX control event procedures, primitive-type-name can specify the built-in ABL data type that maps to the COM object data type of an ActiveX event parameter. The following table shows how the COM object data types for event parameters (shown as ActiveX data types) map to ABL data types.
ActiveX data type4 | ABL data type |
---|---|
Array | ABL array variable |
Array of bytes | RAW |
Boolean (2-byte integer) | LOGICAL |
Currency (8-byte integer with fixed decimal point) | DECIMAL |
Date | DATE DATETIME DATETIME-TZ |
Decimal | DECIMAL |
Double (8-byte floating point) | DECIMAL |
Error Code | INTEGER |
Float (Single) | DECIMAL |
Integer (2-byte integer) | INTEGER |
Long (4-byte integer) | INTEGER |
Object (32-bit value) | COM-HANDLE |
String (character string type) | CHARACTER LONGCHAR |
Signed Byte | INTEGER |
Signed Long (4-byte integer) | INTEGER |
Signed Short (2-byte integer) | INTEGER |
Signed 8-byte integer | INT64 |
Unsigned Byte | INTEGER |
Unsigned Long (4-byte integer) | INT64 |
Unsigned Short (2-byte integer) | INTEGER |
Unsigned 4-byte integer | INT64 |
Unsigned 8-byte integer | DECIMAL |
Variant (variable type) | <ANYTYPE>5 |
You cannot directly specify the type name of a .NET mapped object type (such as System.Int32). To define a parameter that matches a .NET mapped type, you must define it as the corresponding ABL primitive type (primitive-type-name).
For a class or interface return value, ABL passes an object reference associated with the class or interface, not a class instance itself. For more information on object references, see the Class-based object reference reference entry.
The EXTENT is part of the parameter data type. For more information, see the Type-name syntax reference entry.
An indeterminate array parameter can be in one of two states: fixed or unfixed, meaning it either has a fixed dimension or it does not. An indeterminate array parameter has an unfixed dimension when first defined. You can fix the dimension of an unfixed indeterminate array parameter by:
ABL treats a fixed indeterminate array parameter as a determinate array parameter; that is, its size is fixed. The AVM determines the size of an unfixed indeterminate array parameter at run time.
You cannot pass an unfixed indeterminate array to a COM object, DLL routine, or UNIX shared library routine.
If you want to define a parameter that is like an array variable or field, using the LIKE option, but you do not want the parameter to be an array, you can use EXTENT 0 to indicate a non-array parameter.
If you are using the AS option and you do not use the EXTENT option (or you specify constant as 0), the parameter is not an array parameter. If you are using the LIKE field option and you do not use the EXTENT option, the parameter uses the extent defined for the database field you name (if any).
Use the TEMP-TABLE option to define a buffer parameter for a temp-table when the temp-table has the same name as a database table. Otherwise, ABL associates the buffer with the database table by default. Note that you can define a temp-table buffer parameter only for an internal procedure that you define in an external procedure where the temp-table specified by table-name is already defined.
If you use the PRESELECT option and access the buffer parameter in a DO or REPEAT block, the AVM creates an internal list of the records selected. The PRESELECT option tells the AVM to apply that internal list to the buffer you define.
You can pass a temp-table parameter to both local and remote procedures. The AVM passes the parameter by value, by default. That is, the caller and the called routine each have their own instance of the temp-table. When you invoke the RUN statement, the AVM deep-copies the parameter from one instance to the other. The table that is copied depends on whether the parameter is INPUT, OUTPUT, or INPUT-OUTPUT. When you pass a temp-table as an INPUT parameter, the AVM replaces the receiving instance with the source instance, by default. You can also append the copied instance to the end of the receiving instance by specifying the APPEND option. For more information about the APPEND option, see the option description later in this reference entry.
When passing a temp-table parameter to a local procedure, you can override the default deep copy and pass the parameter by reference or by binding (that is, by specifying the parameter in a RUN statement using either the BY-REFERENCE or BIND option). Passing a temp-table parameter by reference or by binding allows the caller and the called routine to access the same object instance (instead of deep-copying the parameter).
For more information about passing a temp-table parameter by reference or by binding, see the Parameter passing syntax reference entry. For more information about temp-table parameters, see OpenEdge Getting Started: ABL Essentials.
You can pass a ProDataSet object parameter to both local and remote procedures. The AVM passes the parameter by value, by default. That is, the caller and the called routine each have their own instance of the object. When you invoke the RUN statement, the AVM deep-copies the parameter from one instance to the other. The ProDataSet that is copied depends on whether the parameter is INPUT, OUTPUT, or INPUT-OUTPUT. When you pass a ProDataSet as an INPUT parameter, the AVM replaces the receiving instance with the source instance, by default. You can also append the copied instance to the end of the receiving instance by specifying the APPEND option. For more information about the APPEND option, see the option description later in this reference entry.
When passing a ProDataSet object parameter to a local procedure, you can override the default deep copy and pass the parameter by reference or by binding (that is, by specifying the parameter in a RUN statement using either the BY-REFERENCE or BIND option). Passing a ProDataSet object parameter by reference or by binding allows the caller and the called routine to access the same object instance (instead of deep-copying the parameter).
For more information about passing a ProDataSet object parameter by reference or by binding, see the Parameter passing syntax reference entry. For more information on ProDataSet object parameters, see OpenEdge Development: ProDataSets.
When you define a reference-only object in the calling routine, and you want to bind that object definition to an object instance in the called routine, define the parameter by specifying the BIND option in an INPUT or INPUT-OUTPUT parameter definition. When you define a reference-only object in the called routine, and you want to bind that object definition to an object instance in the calling routine, define the parameter by specifying the BIND option in an OUTPUT parameter definition. In either case, the reference-only object definition remains bound to the object instance until the routine containing the reference-only object definition is deleted or terminates.
You can bind multiple reference-only object definitions to the same object instance. You can also bind a single reference-only object definition to the same object instance multiple times without generating an error. However, you cannot bind a single reference-only object definition to multiple object instances.
When passing one of these parameters to a remote procedure, the AVM ignores the BIND option and deep-copies the parameter based on the specified parameter mode.
For more information about passing these parameters by binding, see the Parameter passing syntax reference entry.
In the following examples, the r-runpar.p procedure runs a subprocedure called r-param.p and passes the subprocedure an INPUT parameter. The subprocedure r-param.p displays the INPUT parameter.
r-runpar.p
r-param.p
DEFINE INPUT PARAMETER int-param AS INTEGER NO-UNDO. DISPLAY int-param LABEL "Integer input param" WITH SIDE-LABELS. |
In the following example, the r-runpr1.p procedure runs a subprocedure called r-param1.p. This example illustrates the use of multiple parameters and shows that the parameters must be passed in the proper order and must be of the same data type. Note that if you do not specify a parameter type in the RUN statement, the AVM assumes it is an input parameter.
r-runpr1.p
DEFINE VARIABLE new-param AS CHARACTER NO-UNDO FORMAT "x(20)". DEFINE VARIABLE out-param AS DECIMAL NO-UNDO. DEFINE VARIABLE in-param AS INTEGER NO-UNDO INITIAL 20. RUN r-param1.p (OUTPUT out-param, 10, OUTPUT new-param, in-param). DISPLAY out-param LABEL "Updated YTD Sales" SKIP new-param LABEL "Status" WITH SIDE-LABELS. |
r-param1.p
DEFINE OUTPUT PARAMETER xout-param AS DECIMAL NO-UNDO. DEFINE INPUT PARAMETER newin AS INTEGER NO-UNDO. DEFINE OUTPUT PARAMETER xnew-param AS CHARACTER NO-UNDO. DEFINE INPUT PARAMETER xin-param AS INTEGER NO-UNDO. FOR EACH Customer NO-LOCK: xout-param = xout-param + Customer.Balance. END. DISPLAY xout-param LABEL "Balance" WITH SIDE-LABELS. ASSIGN xout-param = xout-param + newin + xin-param xnew-param = "Example Complete". |
In the following example, the r-runpr2.p procedure displays information from a database table and assigns the value of a database field to a variable called io-param. The variable is passed as an INPUT-OUTPUT parameter to a subprocedure called r-param2.p. The subprocedure r-param2.p performs a calculation on the INPUT-OUTPUT parameter, then passes it back to the main procedure. The r-runpr2.p assigns the value io-param to a database field, then displays io-param.
r-runpr2.p
DEFINE VARIABLE io-param AS INTEGER NO-UNDO. FOR EACH Item: DISPLAY Item.ItemName Item.OnHand WITH 1 DOWN. io-param = Item.OnHand. RUN r-param2.p (INPUT-OUTPUT io-param). Item.OnHand = io-param. DISPLAY io-param LABEL "New Quantity On-hand". END. |
r-param2.p
DEFINE INPUT-OUTPUT PARAMETER io-param AS INTEGER NO-UNDO. DEFINE VARIABLE inp-qty AS INTEGER NO-UNDO. PROMPT-FOR inp-qty LABEL "Quantity Received?". ASSIGN inp-qty. io-param = io-param + inp-qty. |
The following example uses a buffer parameter. The procedure r-bufp.p passes the Customer buffer to the getCustomer internal procedure, which attempts to find a record using that buffer.
r-bufp.p
DEFINE BUTTON btnFind LABEL "Find Customer". DO WITH FRAME frCustomer WITH SIDE-LABELS: ENABLE Customer.CustNum btnFind. ON CHOOSE OF btnFind DO: RUN getCustomer (Customer.CustNum:HANDLE, BUFFER Customer). IF NOT ERROR-STATUS:ERROR THEN DISPLAY Customer EXCEPT Customer.Comments WITH SIDE-LABELS. END. ON ENTRY OF Customer.CustNum HIDE MESSAGE. END. WAIT-FOR WINDOW-CLOSE OF CURRENT-WINDOW. PROCEDURE getCustomer: DEFINE INPUT PARAMETER hWidget AS HANDLE NO-UNDO. DEFINE PARAMETER BUFFER bufCustomer FOR Customer. FIND bufCustomer WHERE bufCustomer.CustNum = INTEGER(hWidget:SCREEN-VALUE) NO-LOCK NO-ERROR. IF NOT AVAILABLE bufCustomer THEN DO: MESSAGE "Customer record not found." VIEW-AS ALERT-BOX. RETURN ERROR. END. END. |
The following example defines parameters for the DLL routine, MessageBox, which displays a message on the screen:
r-dllex1.p
DEFINE VARIABLE result AS INTEGER NO-UNDO. MESSAGE " It's a whole new world!" VIEW-AS ALERT-BOX MESSAGE BUTTONS OK TITLE "ABL Message". RUN MessageBoxA (0, " It's a whole new world, again!!", "ABL DLL access", 0, OUTPUT result). PROCEDURE MessageBoxA EXTERNAL "user32.dll": DEFINE INPUT PARAMETER hwnd AS LONG. DEFINE INPUT PARAMETER mbtext AS CHARACTER. DEFINE INPUT PARAMETER mbtitle AS CHARACTER. DEFINE INPUT PARAMETER style AS LONG. DEFINE RETURN PARAMETER result AS LONG. END. |
For more information about passing parameters by reference or by binding, see the Parameter passing syntax reference entry.
When passing a LONGCHAR parameter to a COM object, the AVM passes only the text string (not the code page information). When receiving a text string from a COM object into a LONGCHAR parameter, the AVM converts the text string to the code page associated with the LONGCHAR parameter only if the LONGCHAR has a fixed code page. Otherwise, the AVM sets the LONGCHAR code page to UTF-16. If the AVM cannot convert a LONGCHAR, it raises a run-time error.
When passing a DATETIME or DATETIME-TZ parameter to a COM object, the AVM represents the time to the millisecond. When passing a DATETIME-TZ parameter to a COM object, the AVM first converts the DATETIME-TZ value relative to the local session's date and time, and then drops the time zone.
When receiving a date from a COM object into a DATETIME or DATETIME-TZ parameter, the AVM represents the time to the millisecond. When receiving a date from a COM object into a DATETIME-TZ parameter, the AVM sets the time zone to the local session's time zone.
You can override this default behavior to allow the calling procedure and the called procedure to access the same object instance by passing the TABLE-HANDLE parameter by reference or by binding (that is, by specifying the parameter in a RUN statement using either the BY-REFERENCE or BIND option). If you specify the BIND option in the RUN statement, you must also specify the BIND option in the DEFINE PARAMETER statement.
If the original handle is not the Unknown value (?), the caller's existing table must match the table being received from the called routine.
You can override this default behavior to allow the calling procedure and the called procedure to access the same object instance by passing the DATASET-HANDLE parameter by reference or by binding (that is, by specifying the parameter in a RUN statement using either the BY-REFERENCE or BIND option). If you specify the BIND option in the RUN statement, you must also specify the BIND option in the DEFINE PARAMETER statement.
If the parameter is OUTPUT DATASET-HANDLE, and the caller's handle is the Unknown value (?), no definition is sent to the called routine.