Release 10.1A: OpenEdge Development:
Progress Dynamics Advanced Development

> ## Managing procedures and containers

> The central purpose of the Session Manager is to control all the running objects in the system, including the other managers, application components, and supporting business logic procedures. Much of this work happens automatically, based on information defined in many places, such as:

> - The configuration file and Connection Managers, which define which managers are started for each `Session` `Type`, what the startup options are, etc.

> - Menus and toolbars, which launch other objects, both static and dynamic, on `Choose` of a button or menu item, as defined in the Toolbar and Menu Designer.

> - Definitions of custom super procedures for objects in the object property sheets or the Repository Maintenance tool, which cause the Session Manager to start these supporting objects and make them super procedures.

> - Application code that starts and makes requests of business logic procedures.

> This section describes the procedures in the Session Manager’s API that you can use in your applications to control the running of other application objects, both static and dynamic.

> ##### Using launchProcedure and launch.i

> Call `launchProcedure` to start any persistent procedure your application needs, as shown:

>     RUN launchProcedure IN gshSessionManager
>         ( INPUT pcPhysicalName,
>           INPUT plOnceOnly,
>           INPUT pcOnAppserver,
>           INPUT pcAppserverPartition
>           INPUT plRunPermanent,
>           OUTPUT phProcedureHandle  )

> See OpenEdge Development: Progress Dynamics Managers API Reference for more information on this call. Your code should normally not run `launchProcedure` directly. Instead, the launch.i and `dynlaunch.i` include files act as a wrapper for calls to `launchProcedure`, allowing you to name both an external procedure to run and also the name of an entry point inside it, along with any `INPUT` and `OUTPUT` parameters to the internal procedure and other details that help encapsulate the calls. `dynlaunch.i` is the generally preferred include file to use if you do not require access to the server-side procedure after your request completes. It deals with the entire request in a single AppServer call.

> ##### Using launchContainer

> You have already seen the `launchContainer` call in action many times. This is what the Dynamic Launcher uses to start a dynamic container that you must test. It is what the AppBuilder runs if you select the runner icon for an open container. It is also used from the toolbar and menu support code in `toolbar.p` to start containers that are run on `Choose` of a menu item or toolbar button.

> You can use `launchContainer` within your own application code as well. One important use is to help you integrate existing menus or windows in an older application with new modules that you’re developing in Progress Dynamics. Buttons or menu items added to your current application can launch dynamic containers built in Progress Dynamics, so that both can become part of a single integrated application. This section shows an example of how to do this.

> First look at the `launchContainer` call itself, as shown:

>     RUN launchContainer IN gshSessionManager
>         ( INPUT pcObjectFileName,
>           INPUT pcPhysicalName,
>           INPUT pcLogicalName,
>           INPUT plOnceOnly,
>           INPUT pcInstanceAttributes,
>           INPUT pcChildDataKey,
>           INPUT pcRunAttribute,
>           INPUT pcContainerMode,
>           INPUT phParentWindow,
>           INPUT phParentProcedure,
>           INPUT phObjectProcedure,
>           OUTPUT phProcedureHandle,
>           OUTPUT pcProcedureType).

> The `launchContainer` call takes the following parameters:

> - `INPUT pcObjectFileName (CHARACTER)` — The object filename used when you do not know the physical and logical names. Use this parameter to launch a physical object (static procedure) rather than a dynamic object.

> - `INPUT pcPhysicalName (CHARACTER)` — The physical object name (with path and extension) if known. The difference between this and the object filename can be confusing. This is not an individual static procedure to support a single window. Rather, it is the single driver procedure that instantiates all windows at run time. For standard dynamic windows, always set this parameter to the procedure `ry/uib/rydyncontw.w`, which is the standard framework procedure used to create any dynamic container window. For Progress Dynamics TreeView windows, specify the file `ry/uib/rydyntreew.w`.

> - `INPUT pcLogicalName (CHARACTER)` — The logical object name of the container. This is the name you give to the container window when you create it.

> - `INPUT plOnceOnly (LOGICAL)` — This logical flag indicates whether there might be more than one instance of this procedure running concurrently. If it is `FALSE`, then the Session Manager checks whether there is already a running instance of the object in memory, and if so, reuses that. There is a Progress Dynamics ADM2 container property called MultiInstanceActivated that is set to reflect the user preference for multiple windows. Users can set this in the File Preferences window from the Progress Dynamics Development or Administration windows. This choice is overridden if the object does not support multiple instances as identified by the `MultiInstanceSupported` container property. If this is `FALSE`, then only one instance will ever be run, regardless of the `OnceOnly` value passed in. This is general for object controllers and filter windows.

> - `INPUT pcInstanceAttributes (CHARACTER)` — The SmartObject instance attributes and values to pass to the container, if any. If an instance attribute list is passed in, the list must be in the same standard ADM2 format as returned to the function `instancePropertyList`, with `CHR(3)` between entries and `CHR(4)` between the property name and its value within each entry. These attributes are then set in the container prior to running `initializeobjec`t in the container. The Session Manager procedure `setAttributesInObject` is used to set the attributes.

> - `INPUT pcChildDataKey (CHARACTER)` — The child data key, if applicable. When you invoke a maintenance window from an object controller browse window, for example, the browse window passes in the key value for the selected row the maintenance window should start on. This is the child data key. If a child data key is passed in and the `OnceOnly` flag is `NO` to enable multiple instances, then a check is made for an existing running instance with the same data key. If one is found, then regardless of the `OnceOnly` flag, this instance is just brought to the top, since it is invalid to have multiple instances of a container for the same data key. Also, if the object itself does not support multiple instances, the data key passed in is set to blank. `ChildDataKey` is a SmartObject property you can query in order to set this parameter correctly, when this is appropriate.

> - `INPUT pcRunAttribute (CHARACTER)` — The run attribute if this is required to pass into the container. This could be specified in the Toolbar and Menu Designer, for example, for the action on a menu item. This run attribute is different from the SmartObject attributes and is not normally used.

> - `INPUT pcContainerMode (CHARACTER)` — This is the initial operating mode for the container: view or update, for example. Pass this in as blank to get the default.

> - `INPUT phParentWindow (HANDLE)` — The parent (caller) window handle, if known. This could be the handle of the window invoking the new container, if you want that to be its parent.

> - `INPUT phParentProcedure (HANDLE)` — The parent (caller) procedure handle, if known.

> - `INPUT phObjectProcedure (HANDLE)` — The parent (caller) object handle, if known. The handle of the object linked to the toolbar that contained the menu can also be passed in, for example, the handle of a browser or viewer. If you use `launchContainer` to invoke new windows from old ones where there is no meaningful parent object, then this parameter can be passed in as the unknown value.

> - `OUTPUT phProcedureHandle (HANDLE)` — The procedure handle of the container being run is returned in this `Output` parameter.

> - `OUTPUT pcProcedureType (CHARACTER)` — The procedure type of the container being run is returned in this `Output` parameter. This is normally the string `ICF`.

> ##### Integrating old and new applications

> This section contains an example of how to use the `launchContainer` procedure and the Session Manager to combine existing application modules and new Progress Dynamics modules in a single application. Figure 6–5 shows a simple application window that represents any window or menu in your current application. This one is a static SmartWindow, but any procedure window or other application procedure will do.

> Figure 6–5: Sample application wIndow

> In the example, you launch Progress Dynamics containers from this window, and then later launch the window itself from a Progress Dynamics menu.

> ##### Creating a sample application window

> The procedure below shows one way to create a window.

> | To create the sample application window:

> 1. Build a new static SmartWindow in the AppBuilder.

> 2. Drop two buttons on and label them Customers and Orders. You can use those or build any similar objects of your own to complete the example.

> 3. If you use the Progress Dynamics version of the AppBuilder to create a new static SmartWindow, it will refer to the include file`globals.i` already in the Definition section, as every Progress Dynamics procedure does. Otherwise, you must add it to your procedure. Also, define two variables at the scope of the procedure to hold the handles of the `Customer` and `Order` windows to launch, as shown:

>     {src/adm2/globals.i}
>         DEFINE VARIABLE ghCustomerWin AS HANDLE     NO-UNDO.
>         DEFINE VARIABLE ghOrderWin    AS HANDLE     NO-UNDO.

> 4. Create an internal procedure called `launchDynWindow`. This takes as an `INPUT` parameter the logical name of the window to launch, and returns its procedure handle as an `OUTPUT` parameter. The parameters passed to `launchContainer` should be clear from the previous explanation of the procedure. As noted, the first argument (`ObjectFileName`) is not used. Instead, the name of the dynamic container procedure is passed in, along with the logical name of your container. The `ParentWindow` argument is the handle of the window in the sample procedure, which in our case is `wiWin`. The `ParentProcedure` parameter is its procedure handle, as shown:

>     PROCEDURE launchDynWindow:
>     /*---------------------------------------------------------------------
>       Purpose:     Uses the launchContainer procedure in the Session Manager
>                    to run a dynamic window from this static window.
>       Parameters:  INPUT pcWindowName AS CHARACTER -- the logical window name,
>                    OUTPUT phProcedureHandle AS HANDLE -- the new window handle
>       Notes:
>     ---------------------------------------------------------------------*/
>       DEFINE INPUT  PARAMETER pcWindowName      AS CHARACTER  NO-UNDO.
>       DEFINE OUTPUT PARAMETER phProcedureHandle AS HANDLE     NO-UNDO.
>       DEFINE VARIABLE cProcedureType       AS CHARACTER  NO-UNDO.

>       RUN launchContainer IN gshSessionManager
>         ( INPUT /* pcObjectFileName */    "",
>           INPUT /* pcPhysicalFileName */  "ry/uib/rydyncontw.w",
>           INPUT /* pcLogicalName */        pcWindowName,
>           INPUT /* plOnceOnly */           YES,
>           INPUT /* pcInstanceAttributes */ "",
>           INPUT /* pcChildDataKey */       "",
>           INPUT /* pcRunAttribute */       "",
>           INPUT /* pcContainerMode */      "view",
>           INPUT /* phParentWindow */       wiWin,
>           INPUT /* phParentProcedure */    THIS-PROCEDURE,
>           INPUT /* phObjectProcedure */    ?,
>           OUTPUT   phProcedureHandle,
>           OUTPUT    cProcedureType         /* ICF */    ) .
>     END PROCEDURE.

> 5. Create two trigger blocks. The first is for the `Choose` trigger on the Customer button. Use as the `INPUT` parameter the name of one of the logical container objects from the tutorial application or any others that you have built, as shown:

>     DO:
>         RUN launchDynWindow (INPUT 'custbrowsewin',
>                              OUTPUT ghCustomerWin).
>     END.

> This second block of code is for the `Choose` trigger on the Order button, as shown:

>     DO:
>       RUN launchDynWindow (INPUT 'orderbrowsewin',
>                              OUTPUT ghOrderWin).
>     END.

> 6. This is all you need to do to integrate your static window in with the dynamic containers. Run this code to see:

> 7. Select the Customers button to launch the dynamic `Customer` browse window, as shown:

> 8. Save your window as `testlaunch.w`.

> ##### Registering a static window in the Progress Dynamics Repository

> The next example integrates the applications in the opposite direction, invoking this static window from a Progress Dynamics Menu Controller window.

> | To register your static window in the Progress Dynamics Repository:

> 1. From the AppBuilder’s File menu, select Register in Repository. The Register in Repository window appear, as shown:

> 2. Select a Product Module and an object type of SmartWindow.

> 3. Click OK to register your window. Now you can reference it within the Progress Dynamics development tools.

> There are two object attributes that you might need to set differently from the default settings you get when you add the object to the Repository. Specifically, in order for the Toolbar and Menu Designer to know that this is a container object, and that it can be run from a menu, you must set these attributes: Container Object, and Runnable From Menu, as shown:

> 4. To do this, open the Repository Maintenance Tool, enter testlaunch.w as the Object Name, and click Apply.

> 5. Expand the SmartWindow node and the objects node to show `testlaunch.w`.

> 6. Select the More tab in the maintenance folder and check Container Object and Runnable From Menu on. Verify that the Run Persistent attribute is also checked on and save your changes.

> ##### Adding a static window to the Dynamic Menu Controller window

> Here you can use the `oemenuwin` menu that is part of the tutorial application, but any menu will do.

> | To add the static window to a dynamic Menu Controller window:

> 1. Open the Toolbar and Menu Designer, as shown:

> 2. Enter General as the Module. This filters down the list of Items and Bands.

> 3. Expand the Item Categories node and the Sports node. There are two existing items: for `Customer` records and for `Orders`. Add another item here called OldWindow. Alternatively, you can create the item and add it to the proper band in a single operation, by expanding the Bands node, then the Submenu bands node, and right-clicking on the Order Entry Band to bring up the pop-up menu, from which you select Add Item to Band.

> 4. Either way, you define the item as shown:

> 5. Enter OldWindow as the Item Reference and Menu Label, and enter a Description.

> 6. Select Launch as the Action Type, and `testlaunch.w` as the Object Filename. If you create the item under the Sports Item Category before adding the item to the band, then the Item Category will be filled in for you. Otherwise, if you created the new item directly under the band, enter Sports for the Category. Save this new item.

> 7. If you created the item under the Sports Category, you must now expand the Bands and Submenu bands and add the OldWindow Item to the Order Entry Band. Otherwise you simply select the Band Item tab and set the Item sequence to 3 to add it to the menu after the `Customer` records and `Orders` items, as shown:

> 8. Exit the Toolbar and Menu Designer. Because the oemenuwin Menu Controller uses the Order Entry band, the item you just added to it appears automatically when you run that menu window. Test your change by running `oemenuwin` from the Dynamic Launcher. Click the Destroy ADM Super Procedures toggle box on to clear the client cache of menu items. Your new item appears in the Order Entry menu, as shown:

> 9. Select OldWindow, and the static SmartWindow appears, as shown:

> So now you see how to make changes to both an existing static application, with or without SmartObjects, and to a Progress Dynamics application, to integrate old and new modules in a single session.

> ##### Using launchExternalProcess

> In addition to launching dynamic objects and 4GL windows using the Session Manager, you can also launch external windows processes using the launchExternalProcess call, as shown:

>     RUN launchExternalProcess IN gshSessionManager
>         ( INPUT pcCommandLine,
>           INPUT pcCurrentDirectory.
>           INPUT piShowWindow,
>          OUTPUT piResult   ).

> The call takes these parameters:

> - `INPUT pcCommandLine (CHARACTER)` — The command line to use. For example:

> `notepad.exe` `<filename>`.

> - `INPUT pcCurrentDirectory (CHARACTER)` — The default directory for the process.

> - `INPUTpiShowWindow (INTEGER)` — The show window flag, which can have one of these values:

> - 0) — Hidden
> - 1) — Normal
> - 2) — Minimized
> - 3) — Maximized
> - `OUTPUT piResult (INTEGER)` — The result of the attempted launch action which can be either 0, which indicates failure, or a non-zero value, which is the windows handle of new process.

> The `launchExternalProcess` call uses the CreateProcessA API function in Windows NT or Windows 2000.

> | To see an example of how this works:

> 1. Add another button to your testlaunch.w window labeled Notepad.

> 2. Define this `Choose` trigger for it:

>     DO:
>       DEFINE VARIABLE lResult AS LOGICAL    NO-UNDO.
>       RUN launchExternalProcess IN gshSessionManager
>           (INPUT "Notepad.exe " + THIS-PROCEDURE:FILE-NAME,
>            INPUT "",              /* default directory */
>            INPUT 1,               /* window state -- normal */
>            OUTPUT lResult).
>     END.

> 3. Rerun your window, as shown:

> 4. Choose the Notepad button to bring up the MS Windows Notepad program to edit the current procedure. In this case, because it’s being invoked from the AppBuilder, you see the temporary file the AppBuilder creates for the procedure you’re working on, as shown:

Copyright © 2005 Progress Software Corporation www.progress.com Voice: (781) 280-4000 Fax: (781) 280-4095