Closing Form Instances

riktek

Member
Local time
Today, 14:55
Joined
Dec 15, 2023
Messages
124
A few of us were putting heads together the other day to resolve some difficulties around closing form instances and I thought I'd report back.

What's new recently in the experience of several of us is that apparently, clearing a reference to a form instance is no longer sufficient to close that instance, although it remains necessary. The default behavior, as noted by Allen Browne, had been that removing references to a form instance closes it.

So, apparently, one now must also close the form instance expressly. This requires a DoCmd.Close call but this poses a few difficulties:
- DoCmd.Close only permits object identification by name.
- Each instance of a form has the same name.
- When provided a name, DoCmd.Close operates on the first member of Application.Forms with that name, not the last. This poses no difficulty when closing all instances so long as one gets the number right. One can't specify a specific instance or subset of instances, however, so calling DoCmd.Close, even from the form's module, most likely will close another, or an unintended, instance.

The solution lies in the fact that all DoCmd.Close arguments are optional. If omitted (except perhaps for the Save parameter), the command operates on the active window, but note:
- A form's window does not become active simply because code is executing in its module.
- So, we first must set focus to the form instance intended to be closed.

What we arrived at is:

Code:
Function CloseMe(Optional ByRef objMe As Object) As Boolean

    Dim blnReset As Boolean
   
    If (objMe Is Nothing) Then
        blnReset = True
        Set objMe = Access.Application.CodeContextObject
    End If
   
    objMe.SetFocus
    DoCmd.Close , , acSaveNo

    If blnReset Then Set objMe = Nothing
   
    CloseMe = (Err.Number = 0&)

End Function    'CloseMe()

This is intended to be callable either (a) without an argument as a private function in a form module; or (b) with an argument as a public function in a standard module.

Of course, we may have gotten something wrong, so comments and corrections are welcome.
 
Last edited:
> What's new recently in the experience of several of us is that apparently, clearing a reference to a form instance is no longer sufficient to close that instance
That is not my experience. The Northwind 2 Developer Edition has several such forms, e.g. OrderDetails, and there is no DoCmd.Close to close any instance.
Can you please post a database showing all of your relevant code, and that when we comment out your DoCmd.Close line, the form no longer closes? And/or compare your code with that of NW2? Maybe the discrepancy will then become obvious.
 
Try this: -

Code:
Public Function CloseMe(Optional ByRef objMe As Object) As Boolean
    On Error GoTo ErrHandler

    Dim blnReset As Boolean

    ' If no object passed, assume we're in a form module
    If objMe Is Nothing Then
        blnReset = True
        Set objMe = Access.Application.CodeContextObject
    End If

    ' If it's a control, get its parent form
    If TypeOf objMe Is Access.Control Then
        Set objMe = objMe.Parent
    End If

    ' Ensure it's a form before proceeding
    If Not TypeOf objMe Is Access.Form Then
        Err.Raise vbObjectError + 1, , "CloseMe: Object is not a Form."
    End If

    ' Try to set focus to avoid DoCmd.Close issues
    On Error Resume Next
    objMe.SetFocus
    On Error GoTo ErrHandler

    ' Close the form by name
    DoCmd.Close acForm, objMe.Name, acSaveNo

    ' Clean up if we created the reference
    If blnReset Then Set objMe = Nothing

    CloseMe = True
    Exit Function

ErrHandler:
    CloseMe = False
End Function

Example Usage
From a Form Module: -
Code:
Private Sub btnClose_Click()
    Call CloseMe()
End Sub

From a Standard Module: -
Code:
Public Sub CloseFormByName()
    Call CloseMe(Form_MyForm)
End Sub
 
Last edited:
> What's new recently in the experience of several of us is that apparently, clearing a reference to a form instance is no longer sufficient to close that instance
That is not my experience. The Northwind 2 Developer Edition has several such forms, e.g. OrderDetails, and there is no DoCmd.Close to close any instance.
Can you please post a database showing all of your relevant code, and that when we comment out your DoCmd.Close line, the form no longer closes? And/or compare your code with that of NW2? Maybe the discrepancy will then become obvious.
It was another developer's code, actually, so I can't directly. He was spawning custom message box forms in A365, though, popups but not modal or dialogs. While clearing references in his 32-bit apps continued to work, a client of his flagged that in 64-bit, those forms began remaining open.

My own experience in 64-bit (A2019) is with a timer form. This is an element of a filter class deeply embedded in an application framework without which it won't run, so posting is impractical. The idea, though, is to exploit a form solely for its Timer event. Each keystroke in a FAYT scenario assigns a new timer form instance to a module-level form variable declared WithEvents. The module then sinks that variable's Timer event to run the form or list filter. The effect is to defer filtering until the user stops typing. What happened in my case, concurrently with the other developer's cases, was that filtering often left one or more timer form instances both open and visible.

The same fix worked in both cases.

I put this in the category of "here's the fix if you need it but ignore it otherwise." It's intended to be helpful to anyone who encounters the issue, but doesn't guarantee that everyone will. I wouldn't think to post it if the behavior wasn't confirmed and there weren't two MVPs on the thread.
 
The default behavior, as noted by Allen Browne, had been that removing references to a form instance closes it.
This should still be correct.
Can you provide a reproducible example were it fails?

So, apparently, one now must also close the form instance expressly. This requires a DoCmd.Close call but this poses a few difficulties:
Just send a WM_CLOSE message to the form window.
 
@sonic8 , I thought I had responded the other day but I must not have clicked "Post reply" because it doesn't appear. Apologies, and trying again:

This should still be correct.
Can you provide a reproducible example were it fails?
We thought so, too.

I can't provide the other developer's code directly and mine is embedded deeply in an application framework that can't be abstracted simply, but I detailed the context in both cases in my response to @tvanstiphout . We also know that it seems only to manifest in 64-bit Access, however
Just send a WM_CLOSE message to the form window.
Yes, of course, and thanks. We should patch you in next time. This approach hadn't occurred to any of us but actually is quite elegant because it allows one to exploit Form.hWnd to specify a specific instance or instances, which is precisely the difficulty one has in crafting a fix solely in VBA.
 
My guess is you still have an open pointer to the instances. The code probably sets more than one variable.
 
- So, we first must set focus to the form instance intended to be closed.

If, when each new instance of a form is established, it is assigned to a collection, a specific instance of the form can be referenced by its ordinal position in the collection. Focus can then be set to that instance and the Close method of the DoCmd object called without any further arguments.

The tricky part is knowing the ordinal position of each instance at any one time, as its position in the collection will change as other instances of the form are closed.
 
as its position in the collection will change as other instances of the form are closed.
You can store your forms in an array, collection, dictionary, or custom object. Each option has its quirks. You might even consider creating a custom form store using a class with methods designed for handling multiple form instances.

Anyway, it is a lazy Sunday. I am just passing by to suggest that the OP should use the debugger to check where the forms are being persisted, rather than guessing. Or, like the others say, provide a reproducible example.
 

Users who are viewing this thread

Back
Top Bottom