Try OpenEdge Now
skip to main content
ABL Reference
Handle Reference : Call object handle
 

Call object handle

A handle to a call object allows you to do the following dynamically:
*Invoke an external procedure, internal procedure, or user-defined function
*Invoke a Windows DLL routine or Unix shared library routine
*Get or set an attribute on a handle-based object, such as a buffer or socket
*Run a method on a handle-based object

Syntax

call-object-handle [ :attribute | :method ]
call-object-handle
The handle to a call object.
attribute
An attribute of the call object.
method
A method of the call object. The methods let you set parameters, reset attributes to their default values, and invoke the call object.

Attributes

Methods

Examples

The following fragment dynamically invokes an external procedure non-persistently:
DEFINE VARIABLE hCall AS HANDLE NO-UNDO.

CREATE CALL hCall.

/* Invoke hello.p non-persistently */
hCall:CALL-NAME      = "hello.p".
/* Sets CALL-TYPE to the default */
hCall:CALL-TYPE  = PROCEDURE-CALL-TYPE
hCall:NUM-PARAMETERS = 1.
hCall:SET-PARAMETER(1, "CHARACTER", "INPUT", "HELLO WORLD").
hCall:INVOKE.

/* Clean up */
DELETE OBJECT hCall.
The following fragment dynamically invokes an external procedure persistently, then dynamically invokes one of its internal procedures:
DEFINE VARIABLE hCall AS HANDLE NO-UNDO.

CREATE CALL hCall.

/* Invoke persis.p persistently */
hCall:CALL-NAME  = "persis.p".
hCall:CALL-TYPE  = PROCEDURE-CALL-TYPE
hCall:PERSISTENT = TRUE.

/* IN-HANDLE automatically set to the handle of the persistent procedure */
hCall:INVOKE.

/* Invoke internal-persis-proc in persis.p */
hCall:CALL-NAME      = "internal-persis-proc".
hCall:NUM-PARAMETERS = 1.
hCall:SET-PARAMETER(1, "INTEGER", "INPUT", 333).
hCall:INVOKE.

/* Clean up */
DELETE PROCEDURE hCall:IN-HANDLE.
DELETE OBJECT hCall.
As an alternative to setting the PERSISTENT attribute, a procedure can be run persistently by setting the PROCEDURE-TYPE to "PERSISTENT". Regardless of which attribute is used, the other will automatically be set.
The following fragment dynamically invokes an external procedure as single-run, then dynamically invokes one of its internal procedures:
DEFINE VARIABLE hCall AS HANDLE NO-UNDO.

CREATE CALL hCall.

/* Invoke single.p as a single-run procedure*/
hCall:CALL-NAME  = "single.p".
hCall:CALL-TYPE  = PROCEDURE-CALL-TYPE
hCall:PROCEDURE-TYPE = SINGLE-RUN.

/* IN-HANDLE automatically set to the handle of the single-run procedure */
hCall:INVOKE.

/* Invoke internal-single-proc in single.p */
hCall:CALL-NAME      = "internal-single-proc".
hCall:NUM-PARAMETERS = 1.
hCall:SET-PARAMETER(1, "INTEGER", "INPUT", 333).
hCall:INVOKE.

/* Clean up */
DELETE PROCEDURE hCall:IN-HANDLE.
DELETE OBJECT hCall.
The previous fragment could also be used to dynamically invoke an external procedure as singleton by changing PROCEDURE-TYPE to "SINGLETON".
The following fragment uses a single call object handle multiple times:
DEFINE VARIABLE hCall AS HANDLE NO-UNDO.

CREATE CALL hCall.

/* Invoke hello.p non-persistently */
ASSIGN
  hCall:CALL-NAME      = "hello.p"
  hCall:CALL-TYPE  = PROCEDURE-CALL-TYPE
  hCall:NUM-PARAMETERS = 1.

hCall:SET-PARAMETER(1, "CHARACTER", "INPUT", "HELLO WORLD").
hCall:INVOKE.

/* Reset the call object handle */
hCall:CLEAR.

/* Invoke persis.p persistently */
ASSIGN
  hCall:CALL-NAME  = "persis.p"
  hCall:CALL-TYPE  = PROCEDURE-CALL-TYPE
  hCall:PERSISTENT = TRUE.

/* IN-HANDLE automatically set to the handle of the persistent procedure */
hCall:INVOKE.

/* Invoke internal-persis-proc in persis.p */
ASSIGN
  hCall:CALL-NAME      = "internal-persis-proc"
  hCall:CALL-TYPE  = PROCEDURE-CALL-TYPE
  hCall:NUM-PARAMETERS = 1.

hCall:SET-PARAMETER( 1, "INTEGER", "INPUT", 333).
hCall:INVOKE.

/* Clean up */
DELETE PROCEDURE hCall:IN-HANDLE.
DELETE OBJECT hCall.
The following fragment gets an attribute:
/* Get title of frame */
ASSIGN
  hCall:IN-HANDLE = myframe_handle
  hCall:CALL-TYPE = GET-ATTR-CALL-TYPE
  hCall:CALL-NAME = "TITLE".

hCall:INVOKE.

Mytitle = hCall:RETURN-VALUE.
The following fragment sets an attribute:
/* Set SESSION:NUMERIC-FORMAT to "european" */
ASSIGN
  hCall:IN-HANDLE      = "session"
  hCall:CALL-TYPE      = SET-ATTR-CALL-TYPE
  hCall:CALL-NAME      = "numeric-format"
  hCall:NUM-PARAMETERS = 1.

hCall:SET-PARAMETER( 1, "CHAR", "INPUT", "european").
hCall:INVOKE.
The following fragment drives the call object's INVOKE( ) method from a TEMP-TABLE:
/* Suppose hRuntt is a temp-table that has one record with the following    fields:
parm_1
parm_2
...
parm_n
run-name
nparms
datatypes, extent nparms
iomodes, extent nparms */
DEFINE INPUT PARAMETER TABLE-HANDLE hRuntt.

DEFINE VARIABLE hDtypes AS HANDLE  NO-UNDO.
DEFINE VARIABLE hIOmodes AS HANDLE  NO-UNDO.
DEFINE VARIABLE hCall AS HANDLE  NO-UNDO.
DEFINE VARIABLE ix       AS INTEGER NO-UNDO.

ASSIGN
  hDtypes = hRuntt:BUFFER-FIELD("datatypes")
  hIOmodes = hRuntt:BUFFER-FIELD("iOmodes").

hRuntt:FIND-FIRST.

CREATE CALL hCall.
ASSIGN
  hCall:CALL-NAME      = hRuntt:BUFFER-FIELD("run-name"):BUFFER-VALUE
  hCall:NUM-PARAMETERS = hRuntt:BUFFER-FIELD("nparms"):BUFFER-VALUE.

DO ix = 1 to hCall:NUM-PARAMETERS:
  hCall:SET-PARAMETER(ix, hDtypes:BUFFER-VALUE(ix),
    hIOmodes:BUFFER-VALUE(ix), hRuntt:BUFFER-FIELD(ix):BUFFER-VALUE).
END.

hCall:INVOKE.
DELETE OBJECT hCall.
/* If there are output parms, get values from hRuntt:BUFFER-FIELD(ix) */
The following fragment implements an ABL function, sleep, which causes the AVM to sleep for a specified number of milliseconds:
FUNCTION sleep RETURNS INTEGER (INPUT msecs AS INTEGER):
  DEFINE VARIABLE cFunction AS CHARACTER NO-UNDO INITIAL "sleep".
  DEFINE VARIABLE cLibrary  AS CHARACTER NO-UNDO INITIAL "libc.so.1".
  DEFINE VARIABLE hCall     AS HANDLE    NO-UNDO.

  CREATE CALL hCall.
  ASSIGN
    cLibrary             = "kernel32.dll" WHEN OPSYS = "WIN32"
    cFunction            = "Sleep" WHEN OPSYS = "WIN32"
    hCall:CALL-NAME      = cFunction
    hCall:LIBRARY        = cLibrary
    hCall:CALL-TYPE      = DLL-CALL-TYPE
    hCall:NUM-PARAMETERS = 1.

  hCall:SET-PARAMETER(1, "LONG", "INPUT", msecs).
  hCall:INVOKE( ).
  
  DELETE OBJECT hCall.
  RETURN msecs.
END FUNCTION.
Note that the code checks to determine on which OS it is running, and invokes the appropriate Windows DLL or UNIX shared library.

Notes

*Invoking logic dynamically requires many more lines of code and is less efficient than invoking it statically. You typically use the call object when you cannot use the RUN statement, the DYNAMIC-FUNCTION() function, or widget:attribute or widget:method syntax, as in the following situations:
*To invoke an internal or external procedure whose calling sequence (number of parameters and the data type of each) is unknown at compile time.
If only the name of the procedure is unknown at compile time, use the RUN statement with the VALUE option—and avoid the call object altogether.
*To invoke a function whose calling sequence is unknown at compile time.
If only the name of the function is unknown at compile time, use the DYNAMIC-FUNCTION() function—and avoid the call object altogether.
*To reference a widget attribute or method whose name is unknown at compile time.
*To invoke a Windows DLL routine or Unix shared library routine when:
*The number of parameters and their data type is only known at run time
*The routine exists in both a Windows DLL and a Unix shared library
*The routine has a variable number of parameters
If you already know the name of the attribute or procedure, you know its syntax, since the name implies certain syntax. And if you know the syntax, you know the calling sequence, since the syntax defines the calling sequence. And if you know the calling sequence, you can use widget:attribute or widget:method syntax—and avoid the call object altogether.
*To create a call object, use the following syntax:
CREATE object-handle [ IN widget-pool ]
For example:
CREATE CALL hCall.
Note: Unlike most ABL objects, the call object, by default, goes into the SESSION widget pool, not into the closest unnamed widget pool.
*To delete a call object, use the following syntax:
DELETE OBJECT handle.
For example:
DELETE OBJECT hCall.
Since the call object, by default, goes into the SESSION widget pool, not into the closest unnamed widget pool, to delete a call object created when the IN widget-pool option is not used, use the DELETE OBJECT handle syntax explicitly.
*Setting the PROCEDURE-TYPE attribute to "PERSISTENT" will automatically set the PERSISTENT attribute to TRUE. Likewise, setting the PERSISTENT attribute to TRUE will automatically set PROCEDURE-TYPE to "PERSISTENT". Setting the PROCEDURE-TYPE and PERSISTENT attributes to conflicting values, e.g., PERSISTENT as TRUE and PROCEDURE-TYPE as "SINGLE-RUN", will result in a run-time error.

See also

RUN statement