Unload causes Form_Load Event???

GebhartBob
GebhartBob used Ask the Experts™
on
    In our MDI application, the child forms exit by calling a common, public FormExit Sub in a code module. FormExit does a lot of stuff that works fine, but then we do the Unload, and something weird happens. Here's the code:

     ---Other Code---
     Debug.Print "1"
     DoEvents
     Unload frm       ' "frm" is Set to the child form object in prior code
     Debug.Print "2"
     DoEvents
     Debug.Print "3"
 
 
     We also put this code as the first line of the Form_Load Event Sub of our MDI child forms:
 
     Debug.Print "Form_Init: " & Me.name
 
 
     Here's the debug display we get when we unload any MDI child form:
 
Form_Init: frmChild..
1
2
Form_Init: frmChild..
3
 
 
     I come to this conclusion: The Unload causes the Form_Load Event to fire. How can that be?
 
     Your thoughts will be appreciated.
Comment
Watch Question

Do more with

Expert Office
EXPERT OFFICE® is a registered trademark of EXPERTS EXCHANGE®
Mike McCrackenSenior Consultant
Most Valuable Expert 2011
Top Expert 2013

Commented:
Delete the debug.print "3" and see what you get.

mlmcc

Author

Commented:
mlmcc---
 
     I get exactly the same thing, except missing the last "3" line, i.e.:
 
Form_Init: frmChild..
1..
2..
Form_Init: frmChild..
 
Something is referencing a property on the form while it is unloading (therefore the Form_Init).  I notice in Form_Init you use Debug.Print "Form_Init: " & Me.name, thereby referencing a form property (me.name).  Do you have the same thing in the Form_Terminate event?  If so, it probably wants to terminate, but references a property on the form and then reloads.
If it's not referenced there' I'd bet something on the form was referenced in the FormExit Sub or somewhere else.

Also check to see that nothing else references the form (an old variable you used to create the form, etc).



Ensure you’re charging the right price for your IT

Do you wonder if your IT business is truly profitable or if you should raise your prices? Learn how to calculate your overhead burden using our free interactive tool and use it to determine the right price for your IT services. Start calculating Now!

Mike McCrackenSenior Consultant
Most Valuable Expert 2011
Top Expert 2013

Commented:
Try deleting the
Debug.Print "2"

mlmcc

Author

Commented:
twalgrave---
 
     What you say makes perfectly good sense, except I am pretty darn sure that nothing before the Unload command caused the Form_Load. I got sure by changing the code slightly to this:
 
 
    ---Other Code---
    DoEvents
    Debug.Print "1"
    DoEvents
    Unload frm       ' "frm" is Set to the child form object in prior code
    Debug.Print "2"
    DoEvents
    Debug.Print "3"


     I got the same thing, i.e.:
 
 
Form_Init: frmChild..
1
2
Form_Init: frmChild..
3
 
 
     The "DoEvents" matters, because they let the Form_Load execute, if it's going to. I believe that means that nothing in "Other Code" previous to that first DoEvents could have caused the problem, right?
 
     Also, the Form_Load occurs immediately after the Unload; it doesn't need the DoEvents to let the Form_Load execute. It therefore seems reasonable to conclude that something in that unloaded module is getting executed as a result of the Unload, but I can't see how that could happen ... famous last words from a programmer!
 
     My first thought was maybe Form_Deactivate was getting executed, so I put a Debug.Print there. Nope, it doesn't fire on an Unload.
 
     Then I thought, "Well, maybe the "_LostFocus" Event fires for the control you're on at Unload time. So I played the Debug.Print game there too, with identical results. No dice.
 
     There are no Form_QueryUnload, Form_Terminate or Form_Unload Events Subs anywhere in the application; I checked carefully. There is an MDIForm_Unload in the Main module, but that only executes when the user shuts down the entire application; again, I checked.
 
     So now I got really serious, and put this statement at the top of every Event Sub in our smallest child module (numbering "xx" 01 to 25, as there were 25 Event Subs in that module):
 
     If flag Then Debug.Print "Ouch!..xx "
 
     Then I coded this in the FormExit Sub:
 
If frm.name = "SmallestMDIChild" Then
   flag = True
   Debug.Print "About to unload form.."
   Unload FormsArray(!FormsArrayIndex)
   Debug.Print "Form unloaded.."
   DoEvents
   flag = False
Else
   Unload FormsArray(!FormsArrayIndex)
End If
 
     I also left a "Debug.Print Form_Load.." at the top of the child's Form_Load event sub.
 
     I needn't have bothered. Not one of the 25 events fired. All I got in the Debug display was this:
 
About to unload form..
Form unloaded..
Form_Load..
 
     I agree with you as to the probable cause, but I can't think of anything else to try.
 
     Well, when you reach an impasse, the thing to do is sleep on it. I'll hit the sack and hope something brilliant occurs to me tomorrow.
 
     If you can think of anything I haven't tried, please let me know. Thanks very much for your help.

Commented:
If you set use Me.name then the form will call itself again to get the value of Name property and that is what is causing the reloading of the form. Set the name of the form to some global variable in the form's load event and remove Me.Name from Unload event. Your problem will be solved.
I can tell you that I duplicated your environment as best I could and I never got the form to re-initialize which leads me to believe that there is indeed an object reference holding somewhere in your code or that you are setting/referencing a form's property during the unload process.  Here's the code I used (I made several iterations, setting a global varm passing the form into the routine, etc, but all produces expected results (no additional Initialize events).

Global frmName As Form

Public Sub UnloadForm()
   
    Debug.Print "1"
    DoEvents
    Unload frmName
    Debug.Print "2"
    DoEvents
    Debug.Print "3"
   
End Sub
Private Sub Command1_Click()
   
    Set frmName = Me
   
    Call UnloadForm
   
End Sub

Private Sub Form_Initialize()
   
    Debug.Print "Form_Init"
   
End Sub

Private Sub Form_Terminate()
Debug.Print "Form_Terminate"
End Sub

Private Sub Form_Unload(Cancel As Integer)
   
    Debug.Print "Form_Unload"
   
End Sub


I even tried putting code to reference a property on the form during the unload (both in the Form_Unload event and in the global routine to unload the form after the form was unloaded.  I only ever got 1 Initialize event, but did manage to get 2 Unloads doing this.

So I'd have to say there's another reference somewhere down the line.

Commented:
Try to put a breakpoint at the form_load event, and look at the stack who triggered this event to be called.
That's a great idea...however my guess is that if you put that break-point in and show the call-stack, you will either see form_load as the only entry, or you will see <non VB code> or whatever it is called as the source.  

Commented:
This happens only with MDI forms i think.

If you reference any property of them they will be created "on the fly" so you dont have to worry about them.

Try to check if the form is loaded before you unload it. (If it is in the Forms collection) if its there unload it, otherwise dont unload it.

rdrunner,
I think you may be on to something.  I ran some tests and here's what I found:

1) If the form was never loaded into memory when the Unload command is issued on it, the Form_Init fires and the debug.print shows up, but the Form_Unload doesn't show up.  However, if you look in the forms collection, it is not there.  So therefore one can conclude that although the form_unload never fired, the form is no longer in memory.  So, all in all I think we may be chasing a problem that doesn't exist.  It is simply that the FORM_Unload didn't fire because the form was never really loaded, only initialized.

2) If the form was loaded at least once, then closed naturally, the Unload command on the form doesn't result in a Form_Init and it doesn't appear in the forms collection (This is the behavior I would expect).  I don't understand why it behaves differently if you have loaded the form at least once, but hey, it does.



Author

Commented:
    Eureka! What a sophisticated ligttle rascal this one was! You were absolutely right, twalgrave, there's no devious magic to it. I did in fact refer to the bloody form, but in the most indirect manner possible.
 
     nahumd deserves part of the credit for this solution, because his idea of putting a break at Form_Load and examining the Call stack broke the log jam.
 
     What I saw when I examined the call stack was that when I exited the child form, the Form_Activate Event Sub of the previous child screen fired, which it should. It in turn called a function "ColorForm". So far, so good. But then I saw "<Non-Basic Code>" followed by that bogus second Form_Load. "What ho?" sez I, "it looks like ColorForm is the villain."
 
     Indeed it was. It referred to our "frm" variable, which I thought was set to the newly-activated form. But no, it was incorrectly still set to my trouble-making child form. So when the new form tried to execute ColorForm, that Sub referenced the child form, and the rest is history...
 
     Once I understood what the problem was, the fix was straightforward, which usually the case.
 
     I'm very grateful to all who lent a hand in this very puzzling situation.
 
     This problem led me to investigate Visual Studio Analyzer, which I will ask about in a separate question.
 
     Again, thanks to all.

Do more with

Expert Office
Submit tech questions to Ask the Experts™ at any time to receive solutions, advice, and new ideas from leading industry professionals.

Start 7-Day Free Trial