To show some of the principles of super procedures in action, you can create one that manipulates windows in a simple way. The super procedure needs to have a single entry point, an internal procedure called alignWindow, to position all windows to the same column.

To create an example super procedure:

  1. From the AppBuilder, select New > Structured Procedure. Check the Procedures toggle box if Structured Procedure is not visible in the Objects list.
    Note: A message is displayed in 64-bit versions of OpenEdge stating that viewing procedures and functions in the AppBuilder tree-view is not supported. You must use the Section Editor to view and edit the procedures and functions.
  2. Check the Procedures toggle box so that this nonvisual program template is in the list.
  3. In the Section Editor, add a new procedure called alignWindow:
    /*---------------------------------------------------------------------
    Purpose: Aligns all windows to the same column position.
    ---------------------------------------------------------------------*/
      TARGET-PROCEDURE:CURRENT-WINDOW:COL = 20.0.
      RETURN.
    END PROCEDURE.

    The TARGET-PROCEDURE handle is the handle of the window procedure that this is a super procedure for. The code simply sets its current window’s column position to 20. Note the use of chained attribute references. You can chain together as many object attributes as you need in a single expression, as long as all the attributes (except the last) evaluate to handles. Also, the COL attribute is of type DECIMAL, so do not forget the decimal on the value 20.0.

  4. Now you need a standard procedure that knows how to start a super procedure. It needs to determine whether it is already running, run it if it is not there, and then make it a super procedure of the requesting procedure.

    Define a new external procedure called h-StartSuper.p with this code:

    /* h-StartSuper.p -- starts a super procedure if not already running,
      and returns its handle. */
      DEFINE INPUT PARAMETER cProcName AS CHARACTER NO-UNDO.
      DEFINE VARIABLE hProc AS HANDLE NO-UNDO.
      /* Try to locate an instance of the procedure already running. */
      hProc = SESSION:FIRST-PROCEDURE.
      DO WHILE VALID-HANDLE(hProc):
        IF hProc:FILE-NAME = cProcName THEN
          LEAVE. /* found it. */
        hProc = hProc:NEXT-SIBLING.
      END.
      /* If it wasn't found, then run it. */
      IF NOT VALID-HANDLE(hProc) THEN
        RUN VALUE(cProcName) PERSISTENT SET hProc.
      /* In either case, add it as a super procedure of the caller. */
      SOURCE-PROCEDURE:ADD-SUPER-PROCEDURE(hProc, SEARCH-TARGET).

    This code looks for a running instance of the procedure name passed in, using the SESSION procedure list. If it is not there, it runs it. Then it adds it as a super procedure of the SOURCE-PROCEDURE, which is the procedure that ran h-StartSuper.p.

  5. Add statements to the main block of both h-CustOrderWin6.w and h-OrderWin.w to get h-StartSuper.p to start h-WinSuper.p and then to run alignWindow:
    MAIN-BLOCK:
    DO ON ERROR UNDO MAIN-BLOCK, LEAVE MAIN-BLOCK
      ON END-KEY UNDO MAIN-BLOCK, LEAVE MAIN-BLOCK:
      RUN h-StartSuper.p (INPUT "h-WinSuper.p"). //add this super procedure
      RUN alignWindow.
      RUN enable_UI.
      ASSIGN cState = Customer.State
        iMatches = NUM-RESULTS("CustQuery").
      DISPLAY cState iMatches WITH FRAME CustQuery.
      APPLY "VALUE-CHANGED" TO OrderBrowse.
    END.

    The following figure is a review of what is happening when you run h-CustOrderWin6.w again:

    Figure 1. Run the sample procedure with a super procedure

    The dotted lines represent transient relationships that are only present during startup. Both h-CustOrderWin6.w and h-OrderWin.w run h-StartSuper.p to get their super procedure. When each runs it in turn, SOURCE-PROCEDURE points back to the procedure that ran it. h-StartSuper.p establishes h-WinSuper.p as the super procedure for each one in turn, and then goes away because it was not run persistent itself. It was only needed to set up the relationships.

    Once the persistent procedures are all set up, each one runs alignWindow. There is no alignWindow procedure in either of the .w’s, so the AVM searches the super procedure stack and locates it in h-WinSuper.p and runs that code. Now alignWindow can refer to TARGET-PROCEDURE to access the window handle inside each of the .w’s.

To add another small layer of complexity:

  1. Add an implementation of alignWindow in h-CustOrderWin6.w:
    /*---------------------------------------------------------------------
      Purpose: Local version of alignWindow for h-CustOrderWin
               to set ROW as well as column.
    ---------------------------------------------------------------------*/
      RUN SUPER.
      ASSIGN THIS-PROCEDURE:CURRENT-WINDOW:ROW = 10.0.
    END PROCEDURE.

    This code uses a RUN SUPER to invoke the standard behavior in h-WinSuper.p, and then adds some more code of its own, in this case to set the ROW attribute of the window.

    So the net effect of these two versions of alignWindow is to set both the COL and the ROW.

  2. Do the same thing in h-OrderWin.w. Define a version of alignWindow that sets ROW to something different from the local code in h-CustOrderWin6.w:
    /*---------------------------------------------------------------------
      Purpose: Local version of alignWindow for OrderWin sets Row to 20.0.
               Parameters: <none>
      Notes:
    ---------------------------------------------------------------------*/
      RUN SUPER.
      THIS-PROCEDURE:CURRENT-WINDOW:ROW = 20.0.
    END PROCEDURE.

Now all Order windows come up initially in the same place, on top of one another. You can drag them around to see all of them. The diagram in the following figure represents this second situation.

Figure 2. Variation on running the sample procedures with a super procedure

When the AVM executes the RUN alignWindow statement, it finds the internal procedure locally and executes it. The local version first invokes the standard behavior in the super procedure and then extends it with its own custom code.

Super procedures might seem like a complicated mechanism, but consider that they are intended to allow you to provide standard behavior for many procedure objects. This means that you can carefully craft the super procedure code for a type of behavior, and then every other procedure that uses that super procedure inherits the behavior automatically and transparently. This is the power of super procedures.