borderAndreaVB free resources for Visual Basic developersborder

borderAndreaVB Visual Basic and VB.NET source code resources - Copyright © 1999-2007 Andrea Tincaniborder

AndreaVB | Forum | News | Downloads | Register | Help | Member List | Statistics | Search | PM | Profile

Print This Topic
Previous Topic (Output that includes ".00" behind)Next Topic (Serial Mouse) New Topic New Poll Post Reply
AndreaVB Forum : VB General : Unwanted retention of variable Solved Topic
Poster Message
Dave Green
Level: Professor


Registered: 20-10-2005
Posts: 90

icon Unwanted retention of variable

Hi all
I can't fathom this one.

This is how it showed itself:
I call a form from an MDI. On initial display everything is ok. Then I unload it.
When I call it again, everything is not ok and I grub around trying to find out why. I call the form the same way each time - no parameters are passed.

This is what I found:
When I first call the form an internal (to the form) setup is run, within this setup I set a module-declared variable to TRUE.

After the form is unloaded, and I re-open it I find that the variable is STILL set to TRUE, (it's this that screws up my form contents - coz it should be FALSE or NOTHING) even though the form was unloaded. If I explicitly set the varable to FALSE during the unload event, then everything is fine of course. However that is a kludge - and I'm baffled as to why a module-declared variable is acting as a globally-declared module. I've never had this before - whenever I've unloaded a form, all it's variables have been reset (as you'd expect), but not this one variable!

Any Ideas!! Please....

____________________________
While Breath.Count>0
       Live(gbRelax)
Wend

12-02-2006 at 10:05 PM
View Profile Send Email to User Show All Posts | Quote Reply
yronium
Level: Moderator


Registered: 14-04-2002
Posts: 907
icon Re: Unwanted retention of variable

Well, Dave, the ideas of mine are: how do you unload the form? Are you sure you really unloaded it (I mean, not just hide it)? And, pardon, what module is the variable declared in? The child form module? (Of course it has to, but...). Are you sure you didn't declare another global variable with the same name (that can bring to unexpected results)? In poor words, I only can think to some hidden mistake, for yes: if you unload a form, all its module's variables are destroyed and their allocated memory space is signed as free.
Try checking the var state step by step with the F8 key, and checking the Local Variables window.
Sorry I can't tell you more, maybe somebody else...

____________________________
Real Programmer can count up to 1024 on his fingers

13-02-2006 at 12:05 AM
View Profile Send Email to User Show All Posts | Quote Reply
JLRodgers
Level: Moderator

Registered: 04-04-2002
Posts: 1617
icon Re: Unwanted retention of variable

Everything that was said plus:
are you sure you don't set the variable in a routine at the form's load (i.e. form_[activate|load|etc])

more likely than not, it's being set to true due to something in the form itself, or by other code. (assuming the other points given aren't true)

____________________________
Everywhere's Local (classifieds, job postings, & more for everycity in the world - user entered)

13-02-2006 at 07:49 AM
View Profile Send Email to User Show All Posts Visit Homepage | Quote Reply
Dave Green
Level: Professor


Registered: 20-10-2005
Posts: 90
icon Re: Unwanted retention of variable

Hi
Thanks for your speedy reply.

I unload the form either with me.unload within the click event of the button or from its control box.

The variable is declared within the general declarations of the form.

There is no variable like it declared globally (I always preceed my globals with a g and my modular variables with an m - but I checked anyway)

No the variable is definately not set during Form Load, Activate, etc (believe me I do lot of checking before I'd bother you guys). Single stepping actually proves the variable comes back immediately in the TRUE state!

I tried declaring with both Private and Dim - same results.

THIS IS THE WORRYING PART!!!
I done a search on MSDN for the lifetime of private variables. Now I couldn't find anything regarding VB6 explicitely, but for VBA it definately states that when a form is unloaded, its private variables are retained!! Experimentation on my part has shown that this appears to be the case for VB6 too!

Like you, I naturally assumed that ALL module-declared variables are dumped and cleared on an unload - it seems that they are not (unless I'm going completely bananas). For safety's sake, I sat up to 2 this morning going through all 30 of the forms in my current app and clearing down all module-declared variables in the form_unload event. (I cringe when I think of all the apps I've produced and distributed - and not done this)

Surely, if this is the case, Microsoft have dropped a clanger by retaining these?? They should certainly make it clearer in their documentation - no mention whatsoever of lifetime of variables in the standard documentation. Also what about all the wasted space hanging around with unused varaibles?

Your comments please...

____________________________
While Breath.Count>0
       Live(gbRelax)
Wend

13-02-2006 at 09:09 AM
View Profile Send Email to User Show All Posts | Quote Reply
JLRodgers
Level: Moderator

Registered: 04-04-2002
Posts: 1617
icon Re: Unwanted retention of variable

Freaky.... if you want something like that to work it won't.

But eh, if you do a "load form1" then put in the form's unload (or probably the calling form, but not really feasible in a MDI interface) "set form1 = nothing" it clears it.  

Probably it's keeping a reference until 1) the program closes, or 2) you outright tell it "I'm done, get rid of the form"



____________________________
Everywhere's Local (classifieds, job postings, & more for everycity in the world - user entered)

13-02-2006 at 04:33 PM
View Profile Send Email to User Show All Posts Visit Homepage | Quote Reply
Dave Green
Level: Professor


Registered: 20-10-2005
Posts: 90
icon Re: Unwanted retention of variable

Hi JLR
Yeah probably setting the form to Nothing would work, I'll have a test later and see (should still be able to it in the MDI with reference to one of its child forms i should think).

Haven't really thought this through (or experimented) - but consider this, if VB retains private variables on forms, does it do the same with class modules if you don't explicitly state "As NeW" when setting an object variable to the class?

I virtually always set new (not in the declaration, as I understand this can cause problems), so I've never come across any problems, but....

Anyway, I'll let you know if setting the form to nothing sorts the problem (although, as I said, I've kludged around it in my form_unload events). Bit naughty of MS though I reckon.

____________________________
While Breath.Count>0
       Live(gbRelax)
Wend

13-02-2006 at 06:04 PM
View Profile Send Email to User Show All Posts | Quote Reply
stickleprojects
Level: Moderator


Registered: 09-09-2002
Posts: 891
icon Re: Unwanted retention of variable

Hi,
I have created a small sample app (attached), and I cannot duplicate this issue.
Am I missing something?
I would suggest you put some code in the Form_Terminate event (even a debug.print), as this should run when the form is destroyed.
Kieron


____________________________
Build it better, faster, quicker, easier.. then fix it (non-offical MS mission statement)

____________________________
Attached:
testvars.zip 2 KB (Downloads: 6)

13-02-2006 at 07:15 PM
View Profile Send Email to User Show All Posts | Quote Reply
Dave Green
Level: Professor


Registered: 20-10-2005
Posts: 90
icon Re: Unwanted retention of variable

Hi Kieron
Thanks for looking into this.

I've done some research. According to the Microsoft Press publication: Hardcore Visual Basic by Bruce McKinney, private variables and their values are retained after a form is unloaded. Only if the form is explicitly set to NOTHING or the app terminates are they cleared down and the space freed up.

Under most circumstances this will not matter as usually the form load event is the first to be fired, but if, like me, you sometimes have a SetUp procedure where the forms controls are initialised and this can (but not necessarily) be called before showing (and hence the form_load doesn't fire until you change a control's value), then if you have a boolean that checks to see if setup was called before showing, then THIS is where it can all go pear-shaped (unless the form is set to nothing, or the variable is reset during form close) as the boolean will retain its value, falsely telling the form that setup has been run.   --- phew!

Worth knowing though as this could cause some headaches, particularly as it appears that the concencus of opinion is (mistakingly) that all private variables are cleared when you unload a form.

Best regards
Dave

____________________________
While Breath.Count>0
       Live(gbRelax)
Wend

14-02-2006 at 06:31 PM
View Profile Send Email to User Show All Posts | Quote Reply
stickleprojects
Level: Moderator


Registered: 09-09-2002
Posts: 891
icon Re: Unwanted retention of variable

Hi Dave,
Interesting.
The app I attached shows no evidence of setting a form to nothing, but the caption is still reset. This caption is a variable. Also, the Terminate event is also fired.

Am I doing something different to your example?
Kieron

PS I believe that Hardcore VB was written around vb4/5 and MS have (finally/attempted to) address issues of reference counts and var destruction since then.

PPS. Using VBs "load" command may cause this issue, so maybe that is what was happening..(?)


[Edited by stickleprojects on 18-02-2006 at 11:01 PM GMT]

____________________________
Build it better, faster, quicker, easier.. then fix it (non-offical MS mission statement)

18-02-2006 at 10:59 PM
View Profile Send Email to User Show All Posts | Quote Reply
Dave Green
Level: Professor


Registered: 20-10-2005
Posts: 90
icon Re: Unwanted retention of variable

Hi Kieron

There follows an extraction from my code. This is all within the form frmTranasaction. Yes "Hardcore" is indeed VB5. Note that the only way I can get this to work is to explicitly set the boolean to False in the unload event.

Thanks again. (how DO you post code on here? - it seems to allow one line only?? - see age is creeping up on me)

By the way if you find the problem is indeed a fault in my logic, please let me know, I will post my address and will ask you all to come round and beat me up.

'Version A.0.6 February 2006
Option Explicit
Private mbIsSetUp As Boolean    'TRUE if the window is opened for a particular transaction from
                                'a call via SetUp(), FALSE if simply opened for general viewing
                                '(goes to latest transaction)


Public Sub SetUp(ByVal TransactionID As Long)
    Dim lcTransaction As clsTransaction
    Dim lcAdmin As clsAdmin
    Dim lcAccountCredit As clsAccount
    Dim lcAccountDebit As clsAccount
    Set lcAccountCredit = New clsAccount
    Set lcAccountDebit = New clsAccount
    Set lcTransaction = New clsTransaction
    mbIsSetUp = True
    With lcTransaction
        .OpenTransaction TransactionID
        If .roErrNoRecord Then
            .ShutTransaction
            Set lcTransaction = Nothing
            MsgBox "No more transactions", vbInformation, gsProject
            Exit Sub
        End If
        txtNumber.Text = TransactionID
blah
blah
blah

'################################################## F O R M #######################################
'Version A.0.6 February 2006
Private Sub Form_Activate()
    Dim llTransactionID As Long
    If Not mbIsSetUp Then
        OpenDB "Transaction"
        With grMy(giRS)
            If .RecordCount = 0 Then
                MsgBox "There are no transactions", vbInformation, gsProject
                CloseDB
                Exit Sub
            End If
            .MoveLast
            llTransactionID = .Fields("TransactionID")
        End With
        CloseDB
        SetUp llTransactionID
    End If
    fraString(0).Left = fraRange(0).Left
    fraType(0).Left = fraRange(0).Left
    fraString(1).Left = fraRange(1).Left
    fraType(1).Left = fraRange(1).Left
    msRealSearchSQL(0) = "SELECT * FROM Transaction WHERE"
    msUserSearchSQL(0) = "Search For Transactions"
End Sub

Private Sub Form_Load()
    Me.Left = Screen.Width / 2 - Me.Width / 2
    Me.Top = Screen.Height / 2 - Me.Height / 2
    OpenDB "SELECT * FROM Month ORDER BY MonthID"
    With grMy(giRS)
        While Not .EOF
            If .Fields("MonthID") > 0 Then
                cmbMonth.AddItem .Fields("MonthID") & "   " & .Fields("Month")
            End If
            .MoveNext
        Wend
    End With
    CloseDB
    cmbMonth.AddItem "All Months"
    cmbMonth.ListIndex = cmbMonth.ListCount - 1
    cmbFMM.ListIndex = 0
End Sub

Private Sub Form_Unload(Cancel As Integer)
    mbIsSetUp = False
End Sub


____________________________
While Breath.Count>0
       Live(gbRelax)
Wend

19-02-2006 at 11:07 AM
View Profile Send Email to User Show All Posts | Quote Reply
yronium
Level: Moderator


Registered: 14-04-2002
Posts: 907
icon Re: Unwanted retention of variable

Only an itch, Dave: are you opening the form by some Load frmMyForm or frmMyForm.Show?
Or are you rather doing a Dim frm As frmMyForm -> Set frm = New frmMyForm -> frm.Show ?
I mean: do you load THE form, or just an instance of it? (And I'm not sure it does matter, anyway...)

____________________________
Real Programmer can count up to 1024 on his fingers

20-02-2006 at 07:20 AM
View Profile Send Email to User Show All Posts | Quote Reply
Dave Green
Level: Professor


Registered: 20-10-2005
Posts: 90
icon Re: Unwanted retention of variable

Hi
If I want to display a particular transaction, then I make a call to frmTransaction.SetUp to, er well, set up the form with the details of that transaction, as soon as one of the controls is altered from within that routine then VB automatically calls the form load event. Program control is passed back to my calling routine when SetUp completes and from there I perform a frmTransaction.Show.

To just view the form (which automatically places the latest transaction in the form) I do not call SetUp from outside, I show the form (frmTransaction.Show) and the boolean (mbIsSetUp) which should be false instructs to display the latest transaction within the form activate event. Its this boolean which isn't being reset (unless explicitly on unload)

So to answer your question, I load the actual form, not an instance.

Best regards
Dave

____________________________
While Breath.Count>0
       Live(gbRelax)
Wend

21-02-2006 at 09:46 AM
View Profile Send Email to User Show All Posts | Quote Reply
steve_w
Level: Moderator


Registered: 18-04-2003
Posts: 1156
icon Re: Unwanted retention of variable

Hi Dave

Try this example, it shows the difference by using an instance.

Create an mdi file and add the following code with two menu options File1 and File2

Private Sub File1_Click()

    Dim frm As Form1
    
    Set frm = New Form1
    
    Load frm
    
    frm.Show

End Sub

Private Sub File2_Click()

    Load Form1

    Form1.Show

End Sub


Then in your child form add the following code

Private flag As Boolean

Private Sub Form_Load()

    MsgBox flag
    
    flag = True
    
    MsgBox flag

End Sub


You will see that the file2 option retains its true value when you load it a second time this is because the form has not been destroyed but the instance is so its variables get reset.

Hope it helps

Steve





[Edited by steve_w on 21-02-2006 at 12:02 PM GMT]

21-02-2006 at 12:00 PM
View Profile Send Email to User Show All Posts | Quote Reply
yronium
Level: Moderator


Registered: 14-04-2002
Posts: 907
icon Re: Unwanted retention of variable

And another thought:
I noticed a difference on behaviour of variables when working with normal module-level public variables or customized properties. I couldn't describe the exact difference here - I should reproduce the same situation, and I have not VB here - but in few words is: if I, right before loading form2, set a public variable of it from form1 it is set before loading; if I set a property of form2 in the same phase, it is set (and the internal variable as well) after loading it.
I mean, it's not the same to do:
' in Form2
Public MyVar As Long

' in Form 1
Form2.MyVar = 3
Load Form2
...or rather:
' in Form2
Dim locMyVar As Long

Public Property Let MyVar(ByVal newvalue As Long) as Long
    locMyVar = newvalue
End Property

' in Form 1
Form2.MyVar = 3
Load Form2

The variable in the second way is set when load phase is complete, the first before beginning.

Not sure if it'd be anyway helpful.

[Edited by yronium on 21-02-2006 at 03:04 PM GMT]

____________________________
Real Programmer can count up to 1024 on his fingers

21-02-2006 at 01:55 PM
View Profile Send Email to User Show All Posts | Quote Reply
Goran
Level: Moderator

Registered: 16-05-2002
Posts: 1681
icon Re: Unwanted retention of variable

quote:
I've done some research. According to the Microsoft Press publication: Hardcore Visual Basic by Bruce McKinney, private variables and their values are retained after a form is unloaded. Only if the form is explicitly set to NOTHING or the app terminates are they cleared down and the space freed up.


This is not only the issue with VB5, but is present in vb6 also. The problem is, when the form is loaded for the first time, Initialize event is fired, and after you unload form, the Terminate event wont fire, so basically form is still in the memory (and its module variables). If you load/show the form again, no initialize event will be fired, since the form is actually aready initialized. Terminate event will occur, either when you close tha app, or set the form explicitly to nothing.

So, to go around it, you can:

1) set the form to nothing (as JL advised you)

2) in from unload event, reset all module variables,  as you suggested

3) there are other ways (like reseting the variables in form_Load event, but then you would need to have Show method as the first line in the public procedure you call, so form_load is executed first), but these two are the easiest to maintain (at least to me).

____________________________
If you find the answer helpful, please mark this topic as solved.
21-02-2006 at 10:46 PM
View Profile Send Email to User Show All Posts | Quote Reply
Dave Green
Level: Professor


Registered: 20-10-2005
Posts: 90
icon Re: Unwanted retention of variable

Thanks all, youve put a lot of thought and work into my question and I really appreciate it.

As a work around I'll probably stick with resetting the boolean in the unload event.

Edit:/
No I won't, on second thoughts I'll set the form to Nothing, that way I won't have it "hanging around" and also it will allow the Form_initialise to fire each time (which may be critical to my code)
End Edit/

Handy to know though and to be aware of.

I'll mark this a solved.

Best regards

Dave  

[Edited by Dave Green on 22-02-2006 at 12:21 AM GMT]

____________________________
While Breath.Count>0
       Live(gbRelax)
Wend

21-02-2006 at 11:11 PM
View Profile Send Email to User Show All Posts | Quote Reply
stickleprojects
Level: Moderator


Registered: 09-09-2002
Posts: 891
icon Re: Unwanted retention of variable

No worries Dave.
Glad we could help (he said, taking cred for the 50 million people who really helped! )
Rgs
K
PS. Thanks for marking the topic as solved.. its helps us a lot

____________________________
Build it better, faster, quicker, easier.. then fix it (non-offical MS mission statement)

22-02-2006 at 12:42 AM
View Profile Send Email to User Show All Posts | Quote Reply
AndreaVB Forum : VB General : Unwanted retention of variable Solved Topic
Previous Topic (Output that includes ".00" behind)Next Topic (Serial Mouse) New Topic New Poll Post Reply
Surf To:


Not Logged In? Username: Password: Lost your password?
Partners: Download Actual Software | Free Software Download
borderAndreaVB free resources for Visual Basic developersborder

borderAndreaVB Visual Basic and VB.NET source code resources - Copyright © 1999-2007 Andrea Tincaniborder