Delete persistent procedures
- Last Updated: April 15, 2024
- 6 minute read
- OpenEdge
- Version 13.0
- Documentation
|
NO-ERROR option suppresses any error message, for example, if the
procedure has already been deleted elsewhere. You can also use the
VALID-HANDLE function to check whether a handle is still valid or
not, such as in this example:
|
When you close one of the Order windows by clicking the close icon in the right-hand corner, the window disappears. Is its procedure really gone? Yes, but this does not happen automatically. It is very important for you to make sure that you remember to clean up persistent procedures when your application is done with them, if the AppBuilder does not do it for you.
In this case, the AppBuilder generated just the code you need to make sure the procedure
is deleted when you close the window. You might remember this code from Introduction to the OpenEdge AppBuilder but it should mean a lot more to you now because you
understand about the THIS-PROCEDURE handle, the
PERSISTENT attribute, and procedure handles. The code is in the
disable_UI internal procedure. To review, here is the sequence
again:
- The main block, which executes as soon as the procedure starts up, sets up a trigger
to
RUNthe internal procedure disable_UI on theCLOSEevent:/* The CLOSE event can be used from inside or outside the procedure to */ /* terminate it. */ ON CLOSE OF THIS-PROCEDURE RUN disable_UI. - The AppBuilder generates code for the
WINDOW-CLOSEevent of the window, which is what fires when you click the Close icon in the window:DO: /* This event will close the window and terminate the procedure. */ APPLY "CLOSE":U TO THIS-PROCEDURE. RETURN NO-APPLY. END. - The
APPLY "CLOSE"statement sets off theCLOSEevent for the procedure handle itself. This runs disable_UI, which not only deletes the window with theDELETE WIDGETstatement but also has the statement to delete the procedure, which might have looked cryptic when you first saw it, but which you should fully understand now:/* Delete the WINDOW we created */ IF SESSION:DISPLAY-TYPE = "GUI":U AND VALID-HANDLE(C-Win) THEN DELETE WIDGET C-Win. IF THIS-PROCEDURE:PERSISTENT THEN DELETE PROCEDURE THIS-PROCEDURE. END PROCEDURE. - The
PERSISTENTattribute on the procedure handle identifies it as a persistent procedure, and theDELETE PROCEDUREstatement deletes it by identifying its handle,THIS-PROCEDURE.
If the AppBuilder did not do this for you, the procedure and all its memory and other resources would sit around until your session ended. This might create quite a mess, not just because of the memory it uses, but because of the possibility of records it might be holding and any other resources that could cause errors or contention in your application. The worst part is that the window itself would be gone, so you would have no visual clue that the procedure is still there.
To test your application so you can see what procedures are in memory:
- Run h-CustOrderWin6.w.
- Select several Orders to display in their window.
- Select the Procedures icon from the
PRO*Tools palette:
The Procedure Object Viewer window appears:
This tool shows that you have the main window and three copies of h-OrderWin.w running. Remember that whenever you run a procedure from the AppBuilder, it saves it to a temporary file and runs the temporary file, so you see a temporary filename such as p41539_h-CustOrderWin6.ab in your temporary file directory instead of its actual procedure filename h-CustOrderWin6.w.
The Procedure Object Viewer window has a host of useful information in it, including all the
INTERNAL-ENTRIESfor any procedure you select from the list. You can also run any internal entry by clicking the Run entry button.If you want to get rid of a running procedure from here, you can click the Delete button. If it is an AppBuilder-generated procedure such as those you are looking at, you can also click the Apply “Close” button, which should execute all the proper cleanup code for the procedure that is associated with the
CLOSEevent. - Close the Customers and Orders window and select in the Procedure Object Viewer.
You should see that all the running procedures, including both the main window and any Order windows you have open, are gone. So, are you done cleaning up?
Not yet! The AppBuilder is doing you another favor here, and it is one that is rather dangerous, because if you forget to test your application outside the AppBuilder, you might not see that you still have work to do. When you click Stop, the AppBuilder deletes any persistent procedures that were started since you first chose the Run button, to make it easier for you to test parts of applications over and over. But when you run your application from outside the OpenEdge tools, you need to take care of your own cleanup. If you were to run h-CustOrderWin6.w from another procedure, open several Order windows, and then close h-CustOrderWin6, the Order windows (and their procedures, of course) would still be running.
To add code to delete those procedures when the main window that starts them up is deleted:
- Go into the Definitions section for
h-CustOrderWin6.w and add these definitions to the end of
the section:
DEFINE VARIABLE cOrderHandles AS CHARACTER NO-UNDO. DEFINE VARIABLE iHandle AS INTEGER NO-UNDO. DEFINE VARIABLE hOrderWindow AS HANDLE NO-UNDO.Your new code uses these variables to save off a list of all the procedure handles of the procedures you create, and then later walks through them and deletes them.
- Add another line to the
CHOOSEtrigger for the BtnOrder/Order Detail button to save off the new procedure handle in a list:DO: DEFINE VARIABLE hOrder AS HANDLE NO-UNDO. RUN h-OrderWin.w PERSISTENT SET hOrder (BUFFER Order). cOrderHandles = cOrderHandles + (IF cOrderHandles NE "" THEN "," ELSE "") + STRING(hOrder). END.To save a list of handles, you need to turn each handle into a
STRING. The commas act as a delimiter between entries in the list. TheIF-THEN-ELSEclause inside parentheses adds a comma only if there is already something in the list. - Go into the main block and add some code just before it runs
disable_UIto clean up those procedure handles:ON CLOSE OF THIS-PROCEDURE DO: /* Cleanup any OrderLine windows that might still be open. */ DO iHandle = 1 TO NUM-ENTRIES(cOrderHandles): hOrderWindow = WIDGET-HANDLE(ENTRY(iHandle, cOrderHandles)). IF VALID-HANDLE (hOrderWindow) THEN APPLY "CLOSE" TO hOrderWindow. END. RUN disable_UI. END.
This DO block turns each handle value back into the right data type
using the WIDGET-HANDLE function. (The function you use is the same one
for all handles, even though this is a procedure handle, not a widget handle, for a
visual object like a button.)
You could execute the DELETE PROCEDURE hOrderWindow NO-ERROR statement.
The NO-ERROR option would let you use the DELETE
PROCEDURE statement without bothering to check whether the handle is still
valid. Remember that the user might or might not have closed it on his own.
But because the h-OrderWin.w procedure has special code to process
the CLOSE event and do additional types of cleanup, it is always better
to APPLY "CLOSE" to an AppBuilder-generated procedure window or any
other procedure that uses the same convention. The VALID-HANDLE check
makes sure that the window has not already been closed and the procedure deleted.