Use a persistent procedure to duplicate code
- Last Updated: July 22, 2025
- 5 minute read
- OpenEdge
- Version 13.0
- Documentation
In some cases, you might want to do just the opposite and create multiple running instances of the same procedure at the same time. Here is a simple example that extends the Customers and Orders window. Each time you select an Order in its browse, the procedure starts an instance of a separate window to display detail for the Order. The supposition is that you want to be able to see multiple Orders at the same time, so each Order you select is opened in a separate window and they all stay open until you close them or until you exit the main procedure.
To use a persistent procedure to duplicate code:
- Select in the AppBuilder. This gives you a new empty design window.
- To give the window a title, press CTRL+Click on the frame to
select the window itself and set the window title to Order
Detail.
C-Winis the AppBuilder’s default name for the window (C for Container):
- Click the DBFields icon in the AppBuilder Palette and click on the new design window.
- From the Table Selector dialog box, pick the Order table.
- From the Multi-Field Selector dialog box, select some of the Order table fields, including the OrderNum, CustNum, OrderDate, PromiseDate, and ShipDate.
- Arrange these fields in your new window so that they look something like this:
As you remember from Introduction to the OpenEdge AppBuilder, the AppBuilder generates a query and other supporting code for you whenever you drop database fields onto a window. In this case, you do not need the query because all you are going to do is display fields from an Order retrieved in the main window.
- Double-click on the frame (outside of any field) to bring up its property sheet.
- Uncheck the Open the Query toggle box so that the code does
not try to open a new Order query when the window is
opened:
Now you are going to pass in the current Order number as an input parameter to the procedure.
- In the Definitions section, add a parameter definition for the Order
buffer:
/* *************************** Definitions ************************ */ /* Parameters Definitions --- */ DEFINE PARAMETER BUFFER Order FOR Order.Note the special syntax you use when you pass a buffer as a parameter. The buffer is not defined explicitly as an
INPUTorOUTPUTparameter. In effect, it acts as anINPUT-OUTPUTbuffer. That is, both the calling and called procedure share the buffer so that changes made to the buffer in the called procedure are visible in the calling procedure.In this case, you do not change the name of the buffer because the AppBuilder gives you a frame definition based on the fields in the Order table. You could change those definitions to use a different buffer name or even to treat the fields just as fill-ins without any connection to the database, but the simplest thing for the example is just to use the definition the AppBuilder provides.
For this example, you do not need to change any data in the Order window (that comes in a later section), so the easiest way to disable all the fields is to use the Properties Window.
- Choose all the fields in the Order window individually (with
CTRL+Click) or by dragging a box around them with the
mouse:
- Select from the AppBuilder menu.
- Double-click on the Enable property to set it to no:
- Click the green checkmark to register the change.
If you also want to set the Read-Only attribute that puts a box around each field, you can only do this in the property sheet for each field individually.
This is all you have to do to the new window. The generated code displays the record automatically, and that is all this procedure needs to do.
- Save the new procedure as h-OrderWin.w.
To add some code to the main window to start up an instance of h-OrderWin.w for each Order you want to see:
- Open h-CustOrderWin5.w and save it as h-CustOrderWin6.w.
- In h-CustOrderWin6.w, drop a new button onto the design window next to the Order browse.
- Name it BtnOrder and give it a label of Order Detail.
- In the Section Editor, give the new button this
CHOOSEtrigger:DO: DEFINE VARIABLE hOrder AS HANDLE NO-UNDO. RUN h-OrderWin.w PERSISTENT SET hOrder (BUFFER Order). END.The code runs h-OrderWin.w as a persistent procedure, passing in the record buffer for the current Order. It sets the
hOrderlocal variable to the procedure handle. Because you do not need the order handle outside of this trigger, you can define theHANDLEvariable locally to the trigger.In fact, the code is not using the handle at all yet, but it will shortly. It is almost never the case that you run a persistent procedure without saving its handle for one purpose or another. In this case, you add code just below to clean up the procedure when the main window is closed.
- Run the window and click the Order Detail button several
times to see different Orders displayed, each in its own
window:
You created multiple running instances of the same persistent procedure. Each has its own memory and data, so that they can display different Order records. If you want to identify them from other procedures, you can use the
PRIVATE-DATAfield to store off the Order number to go along with the procedure name, which is the same for each instance. - You can close the Order Detail windows either individually or when you close the main window, they all go away.