Wiki Home

Releasing All Forms


Namespace: WIN_COM_API
How to reliably release all forms or, for that matter, all the objects in related containership hierarchies?
See Manual Garbage Collection for more on issues pertaining to releasing related containers. Moreover by heeding certain Object Oriented Heuristics, especially the Relationship Heuristics, you can neatly avoid almost all problems related to Ambiguous Or Contentious Object Ownership.-- Steven Black
Additional point here worth mentioning is that the use of an application framework with a solid form manager component makes this issue a no-brainer. As any framework that has a decent form manager in it will be tracking all open forms and will provide a mechanism for shutting all forms down built into the framework thus removing the need to rely on VFP's collections to get all the forms identified. --JimBooth
In order to release all open forms you need to do it backwards through the collection. If the forms use the QueryUnload method to check to make sure the form can release, you'd need to check the results of that as well: (code by George Tasker)
local lnForms, llDone
lnForms = _SCREEN.FormCount
llDone = .T.
DO WHILE lnForms > 0 AND llDone
  ** we need to add Pemstatus check since toolbars are also in the _screen.Forms collection, but don't have QueryUnload method

  if pemstatus(_SCREEN.Forms(lnForms),'QueryUnload' ,5)
     llDone = _SCREEN.Forms(lnForms).QueryUnload()
  endif

  IF llDone
    _SCREEN.Forms(lnForms).Release
    lnForms = _SCREEN.FormCount
  ENDIF
ENDDO


This loop immediately terminates if one of the form can't be closed, so the rest of the forms are left open.
CAUTION This approach may fail in situations where forms contain object reference, especially to other Form objects; the reason is that if you fail to release a Form that contains an object ref to another Form, or a control owned by another form, before releasing the referenced Form, the referenced Form will fail to Release as a result of a dangling object ref. i.e:

  • Form1 is instantiated
  • Form2 is instantiated, and holds an object reference to Form1 called Form2.oForm1Ref
    If Form2 is released, and then Form1 is released, both Forms release normally. If Form1 is released before Form2, the object ref Form2.oForm1Ref still exists, and the object Form1 is not released, since there's still an active reference to the object Form1. If Form2 is now released, a dangling object Form1 remains with no means to clean it up and close normally. In order to find the dangling object reference you can use David Frankenbach utility (available for download from his site) -- Ed Rauh
    In addition, the following code may be used: (code by Ed Rauh)
    ********************************************************************
    *  Description.......: Depart
    *  Calling Samples...:
    *  Parameter List....:
    *  Created by........:  Ed Rauh
    *  Modified by.......:
    ********************************************************************
    FUNCTION Depart
    LPARAMETER tlNoDebug
    CLEAR EVENTS
    POP KEY ALL
    SET ASSERTS ON
    ON SHUTDOWN
    DEACTIVATE WINDOW ALL
    _SCREEN.Hide()
    SET SYSMENU TO DEFAULT
    SET LIBRARY TO
    ASSERT _SCREEN.Show() AND ''=SYS(3056) AND tlNoDebug 'Forms Deactivated'
    WITH _SCREEN
       DO WHILE .FormCount > 0
          .Forms(.FormCount).Release()
       ENDDO
    ENDWITH
    ASSERT tlNoDebug 'Forms Released'
    RETURN .F.

    Contributors: Nadya Nosonovsky, George Tasker, Nick Neklioudov, Ed Rauh
    Category Application Design
  • ( Topic last updated: 2007.07.30 12:41:36 PM )