Defines an internal procedure as an ABL procedure or declares an internal procedure
        prototype for an external routine in a Windows dynamic link library (DLL) or UNIX shared
        library, or for an internal ABL procedure defined in an external procedure that is itself a
        super procedure of the declaration procedure. The following syntax boxes describe the syntax
        for each use of the statement, beginning with an internal procedure definition.
     
    Syntax
      
      
          
          
            
              
                PROCEDURE proc-name[ PRIVATE ] :
  [procedure-body] 
               | 
            
          
        
 
      This is the syntax to declare an internal procedure prototype for a routine in a Windows
        DLL or UNIX shared library, or for an internal ABL procedure defined in a super
        procedure:
      
          
          
            
              
                PROCEDURE proc-name 
  {   EXTERNAL "dllname" [ CDECL | PASCAL | STDCALL ]
         [ ORDINAL n ][ PERSISTENT ][ THREAD-SAFE ]
    | IN SUPER } :
  [ procedure-body ]
               | 
            
          
        
 
      
        
          - 
            proc-name
          
 
          - The name of the internal procedure.
To define the name of an internal ABL procedure
              that is an event handler for ActiveX controls (OCX event procedure), you must specify
                proc-name according to the following syntax:
                
                
                  
                    {control-frame-name.control-name.event-name | ANYWHERE.event-name}
 | 
                  
                
              
 
For more information on naming event handlers for ActiveX controls using this
              syntax, see the notes for this reference entry.
 
              
                - EXTERNAL "dllname"
 
                - Declares the internal procedure as a Windows DLL or UNIX shared
            library routine. The dllname argument, specified as
            a string literal, is the name of the DLL or library containing the routine. The value of
              dllname can contain Unicode characters. See Internationalize ABL Applications for more information about
            Unicode.
 
              
              
                - CDECL
 
                - Tells ABL to use the C calling convention when accessing the routine.
 
              
              
                - PASCAL
 
                - Supported only for backward compatibility. This option is not valid for
                  SpeedScript.
 
              
              
                - STDCALL
 
                - Tells ABL to use the standard Windows calling convention when accessing the
                  routine. This is the default.
Note: The 64-bit Windows GUI and
                    character clients ignore the CDECL, PASCAL, and STDCALL calling conventions if
                    they are specified. The 64-bit Windows GUI and character clients always use the
                    standard 64-bit FASTCALL calling convention.
 
              
              
                - ORDINAL n
 
                - Specifies the number of the DLL entry point (the nth routine)
                  to invoke. If you use the ORDINAL option, then proc-name can
                  specify any name used in the corresponding RUN statement to reference the routine.
                  If you omit the ORDINAL option, proc-name specifies which DLL
                  routine you want to invoke. 
For UNIX shared library routines, this option does
                    not apply and is ignored.
 
              
              
                - PERSISTENT
 
                - Specifies that the DLL or shared library routine should remain loaded in memory
                  until the AVM exits or the session executes the RELEASE EXTERNAL statement.
 
              
              
                - THREAD-SAFE
 
                - Specifies that the DLL or shared library routine is thread
            safe. When a DLL or shared library is marked as THREAD-SAFE, multiple sessions can
            access it simultaneously. This option is only valid when running an application on an
            instance of the Progress Application Server for OpenEdge; otherwise, this option does
            not apply and is ignored.
 
              
              
                - PRIVATE
 
                - Indicates the following about the internal procedure:
                    - It cannot be invoked from an external procedure—that is, from a procedure
                      file external to the current procedure file.
 
                    - The INTERNAL-ENTRIES attribute on the procedure that defines it does not
                      provide its name (unless the procedure that defines it is the current
                      procedure file).
 
                    - The GET-SIGNATURE method on the procedure that defines it does not provide
                      its signature (unless the procedure that defines it is the current procedure
                      file).
 
                  
 
              
              
                - IN SUPER 
 
                - Declares that the definition of the internal procedure resides
            in a super procedure.
 
              
              
                - procedure-body
 
                - The body of an internal procedure definition. Define
                    procedure-body using the following syntax:
             
            
                
                
                  
                    procedure-logic
       .
       .
       .
    [ catch-block [ catch-block...]]
    [ finally-block ]
[ END [ PROCEDURE ] . ]
 | 
                  
                
              
 
 
              
                - procedure-logic
 
                - Zero or more ABL statements, depending on the internal
                  procedure definition or declaration. Each logic statement must end in with a
                  period (.).
If you declare the internal procedure as an ABL
                    procedure, these statements can include executable statements and non-executable
                    statements including definitions of run-time parameters (using the DEFINE
                    PARAMETER statement), local program variables, frames, widgets, and buffers. Any
                    such objects you define within the internal procedure remain in effect only for
                    the life of the internal procedure.
If you are defining
                    the internal procedure for use as an event procedure to handle asynchronous
                    remote requests, you can specify run-time parameters as INPUT only. (Any other
                    type of parameter generates a run-time error.) Each INPUT parameter must
                    correspond in order and data type with an OUTPUT (or INPUT-OUTPUT) parameter as
                    defined in the remote procedure that executes the request.
If you declare the internal procedure as a DLL or UNIX shared
                    library routine (using the EXTERNAL option), these statements can include only
                    DEFINE PARAMETER statements.
For more information on
                    accessing DLL or UNIX shared library routines from ABL, see the topics on DLLs
                    in OpenEdge Programming Interfaces.
 
              
              
                - catch-block
 
                - Specifies a CATCH statement that defines error handling code for one or more
                  error types. A DO block does not have any default error handling. Therefore, a DO
                  block must have error handling options specified such that it becomes an undoable
                  block. Otherwise, ABL generates a compiler warning. For more information on
                    catch-block, see the CATCH statement reference entry.
 
              
              
                - finally-block
 
                - Specifies a FINALLY statement that defines the processing that must occur after
                  all other processing in the block occurs. For more information on
                    finally-block, see the FINALLY statement reference entry.
 
              
              
                - END [ PROCEDURE ]
 
                - Specifies the end of the internal procedure body. If
                    procedure-logic contains one or more statements, you must end
                  the internal procedure body with the END statement.
 
              
             
        
      
     
    Example
      
      The following example declares an ABL internal procedure that computes the factorial of an
        integer entered as an INPUT parameter. The result is returned as an OUTPUT parameter. Note
        that the following procedure calls itself recursively to obtain the result:
      
        r-factrl.p
      
      
          
          
            
              
                DEFINE VARIABLE FactorialResult AS INTEGER NO-UNDO FORMAT ">>>,>>>,>>9".
DEFINE VARIABLE FactorialInput  AS INTEGER NO-UNDO.
REPEAT:
  SET FactorialInput VALIDATE(FactorialInput <= 12 AND FactorialInput >= 0,
    "Value must be between 0 and 12.").
  RUN Factorial (INPUT FactorialInput, OUTPUT FactorialResult).
  DISPLAY FactorialResult.   
END.
PROCEDURE Factorial:
  DEFINE INPUT PARAMETER  PTerm           AS INTEGER NO-UNDO.
  DEFINE OUTPUT PARAMETER FactorialResult AS INTEGER NO-UNDO.
  DEFINE VARIABLE WorkingResult AS INTEGER NO-UNDO.
   
  IF PTerm <= 1 THEN DO:
    FactorialResult = 1.
    RETURN.
  END.
  ELSE DO:
    RUN Factorial (INPUT PTerm - 1, OUTPUT WorkingResult).
    FactorialResult = PTerm * WorkingResult.
  END.
END PROCEDURE. 
               | 
            
          
        
 
      The following example declares a DLL routine, MessageBox(), which displays
        a message: 
      
        r-dllex1.p
      
      
          
          
            
              
                DEFINE VARIABLE iResult 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 iResult).
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.  
               | 
            
          
        
 
      The following code fragment declares a UNIX shared library routine:
      
          
          
            
              
                PROCEDURE atoi EXTERNAL "/usr/lib/libc.so.1":
... 
               | 
            
          
        
 
     
    Notes
      
      
        - You can terminate a PROCEDURE statement with either a period (.) or a colon (:), but
          typically use a colon (:) for a procedure definition or prototype that includes
            procedure-body and a period (.) for a procedure definition or
          prototype that omits any procedure-body.
 
        - You can place an internal procedure definition or declaration before, after, or in the
          middle of your main procedure code. You cannot nest an internal procedure within
          another internal procedure.
 
        - Use the RUN statement to invoke an internal procedure. You can run an internal procedure
          from within the external procedure that defines it, either from the main-line of the
          external procedure or from another internal procedure defined in the external procedure.
          You can also run an internal procedure defined in another external procedure using the IN
            proc-handle option of the RUN statement as long as the external
          procedure meets one of these conditions:
            - It is active on the procedure call stack
 
            - It is an instance of a persistent procedure
 
          
 
        - You cannot define shared objects, work tables, or temp-tables within an internal
          procedure.
 
        - An internal procedure can reference any objects defined in the outer procedure block.
          For example, it can reference variables, buffers (explicit or implicit; shared or
          unshared), variables, run-time parameters, named frames, or temp-tables. If you define an
          object with the same name in the internal procedure and the external procedure, a
          reference within the internal procedure resolves to the local object.
 
        - A buffer explicitly defined in an internal procedure is scoped to the internal
          procedure. Any other buffers are scoped to the outer procedure block.
 
        - To define the internal procedure as an event handler for ActiveX
          controls (OCX event procedure), you must specify proc-name according to the following syntax:
              
              
                
                  
                    { control-frame-name .control-name .event-name
  |  ANYWHERE .event-name
}
                   | 
                
              
            
 
In control-frame-name.control-name.event-name, control-frame-name is the name (unquoted) of the
            control-frame that contains the ActiveX control. This is the name that the AppBuilder
            typically assigns to the control-frame (NAME widget attribute) when you insert the
            control into your user interface. The control-name
            is the value (unquoted) that you assign to the control Name property at design time in
            the AppBuilder Property Window. The event-name is
            the name (unquoted) of the ActiveX control event that you want to trigger execution of
            this procedure.
In ANYWHERE.event-name, ANYWHERE specifies an event procedure that handles the
            specified event in any ActiveX control. This event procedure executes only if you have
            not defined a control-frame-name.control-name.event-name
            event procedure that exactly matches the control/event combination at run time.
At design time, the AppBuilder lists the available events for a control
            and automatically creates a template for the OCX event procedure definition from the
            event that you select. For more information on how to create OCX event procedures in the
            AppBuilder, see the information on ActiveX controls in OpenEdge
              Programming Interfaces. For more information on how to work with OCX event
            procedures in an application, see OpenEdge Programming
              Interfaces.
 
        - When you define an OCX event procedure, you can access the component handle (COM-HANDLE
          value) of the control that generates the event at run time using the COM-SELF system
          handle. You can also access the handle of the parent control-frame using the SELF system
          handle.
 
        - The RETURN-VALUE function provides the value returned by the most recently executed
          RETURN statement of a local or remote procedure.
 
        - You use the call object handle to dynamically invoke a Windows DLL routine or UNIX
          shared library routine at run time.