DEFINE PARAMETER statement

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.

Note: To define run-time parameters of a user-defined function, or a method within a class (including constructors), see the Parameter definition syntax reference entry.

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.

Syntax

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 PARAMETER BUFFER buffer-name FOR [ TEMP-TABLE ]table-name
  [ PRESELECT ]
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 ]
  }
INPUT PARAMETER
Defines a parameter that gets its value from one of the following sources:
  • If the calling procedure runs the current (called) procedure synchronously, the value comes from the corresponding INPUT parameter of the RUN statement.
  • If the current procedure is the event procedure specified to handle the PROCEDURE-COMPLETE event for an asynchronous remote procedure, the value comes from the corresponding OUTPUT or INPUT-OUTPUT parameter of the remote procedure.
OUTPUT PARAMETER
Defines a parameter that returns a value to one of the following destinations:
  • If the calling procedure runs the current (called) procedure synchronously, the value is returned to the corresponding OUTPUT parameter of the RUN statement in the calling procedure.
  • If the calling procedure runs the current (called) procedure as an asynchronous remote procedure, the value is returned to the corresponding INPUT parameter of the event procedure specified to handle the PROCEDURE COMPLETE event for the current procedure.
INPUT-OUTPUT PARAMETER
Defines a parameter that receives an initial value passed from the calling procedure that can be subsequently modified by the called procedure. The calling procedure cannot pass a literal value. The called procedure returns the modified value to one of the following destinations:
  • If the calling procedure runs the current (called) procedure synchronously, the value is returned to the corresponding INPUT-OUTPUT parameter of the RUN statement in the calling procedure.
  • If the calling procedure runs the current (called) procedure as an asynchronous remote procedure, the value is returned to the corresponding INPUT parameter of the event procedure specified to handle the PROCEDURE COMPLETE event for the current procedure.
RETURN PARAMETER
Defines a parameter that holds the return value of a DLL or UNIX shared library routine. When the DLL routine returns, the value of this parameter is passed back to the calling procedure. You can only have one RETURN parameter per routine.
parameter
Identifies the name of the parameter you want to define.
AS [ HANDLE TO ]primitive-type-name
Specifies a primitive type for the parameter.

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.

Data types for DLL and UNIX shared library routine parameters
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)
Caution:
For CHARACTER parameters, the AVM always passes the routine a pointer to the character or character string value rather than the value itself. If the routine modifies the value, it can also modify the AVM memory outside the bounds of the CHARACTER value with unpredictable results. For this reason, ABL does not allow you to use OUTPUT or RETURN for CHARACTER or LONGCHAR parameters, as well as CHARACTER or LONGCHAR array parameters, and does not recommend you use INPUT-OUTPUT for CHARACTER or LONGCHAR parameters. Rather, pass the character string as a MEMPTR parameter. For more information, see OpenEdge Development: Programming Interfaces.
Note: You cannot use RETURN for any type of array parameter.

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.

Data types for ActiveX control event procedures
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
AS [ CLASS ]{object-type-name}
Defines the parameter as an object reference with the data type of a class or interface. The default value of the parameter is the Unknown value (?). You cannot assign an initial value using the INITIAL option.
object-type-name
Specifies the type name of an ABL or .NET class or interface. Specify an object type name using the syntax described in the Type-name syntax reference entry. With an appropriate USING statement, you can also specify a class or interface name alone, without the qualifying package or namespace.

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).

CLASS
If the specified class or interface type name conflicts with an abbreviation for a built-in primitive type name, such as INT for INTEGER, you must specify the CLASS keyword.

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.

LIKE, CASE SENSITIVE, FORMAT, DECIMALS, INITIAL, COLUMN-LABEL, LABEL, NO-UNDO
For descriptions of these options, see the DEFINE VARIABLE statement reference entry.
EXTENT [constant ]
Defines the parameter as an array of data elements, where the element data type is specified by the AS primitive-type-name option, the LIKE field option, or the AS object-type-name option. This option can specify an array parameter as either determinate (has a defined number of elements) or indeterminate (has an undefined number of elements). To define a determinate array parameter, specify the EXTENT option with the constant argument. This optional argument is an integer value that represents the number of data elements in the array parameter. To define an indeterminate array parameter, specify the EXTENT option without the constant argument.

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:

  • Setting the number of elements in the array parameter using the EXTENT statement
  • Defining the indeterminate array parameter so that it becomes the target of a determinate array assignment as a passed argument (on INPUT) or as a value returned from the procedure (on OUTPUT), fixing the indeterminate array to the dimension of the determinate array assignment

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).

PARAMETER BUFFER buffer-name FOR [TEMP-TABLE]table-name[PRESELECT]
Defines a buffer parameter, where buffer-name is the name you specify for the buffer and table-name is the name of a temp-table or database table to which the buffer is attached. You can pass a buffer associated with a database table to a buffer parameter. You cannot pass a work table to a buffer parameter. A buffer parameter is always INPUT-OUTPUT. You cannot pass buffer parameters to the AppServer.

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.

TABLE FOR temp-table-name
Defines a temp-table parameter.

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).

Note: When you specify the BIND option in the DEFINE PARAMETER statement, you must also specify the BIND option in the RUN statement.

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.

TABLE-HANDLE temp-table-handle
Defines a temp-table handle parameter.
DATASET dataset-name
Defines a compile-time defined ProDataSet object parameter.

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).

Note: When you specify the BIND option in the DEFINE PARAMETER statement, you must also specify the BIND option in the RUN statement.

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.

DATASET-HANDLE dataset-handle
Defines a ProDataSet object handle parameter.
APPEND
Specifies whether or not to append the data from a source instance to the receiving instance of a passed temp-table or ProDataSet parameter. To append input parameter data, specify the APPEND option in the DEFINE PARAMETER statement. To append output parameter data, specify the APPEND option in the RUN statement.
BIND
Indicates that a TABLE, TABLE-HANDLE, DATASET, or DATASET-HANDLE parameter binds a reference-only object in one routine to an object instance defined and instantiated in another local routine.

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.

Caution:
Do not delete the object or routine to which a reference-only object is bound, or you might be left with references to an object that no longer exists.

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.

BY-VALUE
Specified for an INPUT, OUTPUT, or INPUT-OUTPUT TABLE, TABLE-HANDLE, DATASET, or DATASET-HANDLE parameter in a called routine, this option forces the parameter to be passed to the local routine by value, which overrides any BY-REFERENCE option in the corresponding routine invocation. For more information on BY-REFERENCE, see the Parameter passing syntax reference entry.

Examples

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

RUN r-param.p (INPUT 10).

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.

Notes

See also

DEFINE BUFFER statement, DEFINE VARIABLE statement, DELETE PROCEDURE statement, Parameter passing syntax, RUN statement, Type-name syntax, USING statement