Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations Chris Miller on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

Application-defined or object-defined error 2

Status
Not open for further replies.

1DMF

Programmer
Jan 18, 2005
8,795
GB
Hi,

I have a class I built for sending emails, it works fine, however, I have come across an anomaly I cannot fathom.

Part of the funcitonality is to show a progress window, which is initialised as follows...

Code:
Private Sub Class_Initialize()

    ' Progress window
    bShowProgress = True
    Set oProgress = CreateObject("Scripting.Dictionary")
    oProgress.Add "Msg", cProgressMsg
    Call InitProgress("Progress_Info", "Progress", False, True)
End Sub

' Initialise progress window
Public Sub InitProgress(ByVal sFormName As String, ByVal sTextCtrl As String, ByVal bHide As Boolean, ByVal bClose As Boolean, Optional ByVal sSubFormName As String = "")

'On Error Resume Next

    Dim cTextBox As Access.TextBox
    
    ' Open form if not open
    If Not CurrentProject.AllForms(sFormName).IsLoaded Then
        DoCmd.OpenForm sFormName, acNormal
    End If
    
    ' Hide form
    If bHide Then
        Forms(sFormName).Visible = False
    End If
    
    ' Set textbox control
    If sSubFormName <> "" Then
        Set cTextBox = Forms(sFormName).Controls(sSubFormName).Form.Controls(sTextCtrl)
    Else
        Set cTextBox = Forms(sFormName).Controls(sTextCtrl)
    End If
    
    ' Set progress vars
    oProgress.Add "Frm", sFormName
    oProgress.Add "Ctrl", cTextBox
    oProgress.Add "Close", bClose
    oProgress.Add "Hide", bHide
    
End Sub

' Show progress message
Private Sub ShowProgressMsg(ByVal bHide As Boolean)
    
    On Error GoTo EH_ShowProgressMsg
    
    ' Check if form open
    If Not CurrentProject.AllForms(oProgress.Item("Frm")).IsLoaded Then
        DoCmd.OpenForm oProgress.Item("Frm"), acNormal
    End If
    
    ' Check if form visible
    If Not Forms(oProgress.Item("Frm")).Visible Then
        Forms(oProgress.Item("Frm")).Visible = True
    End If
    
   
    ' Update message window
    oProgress.Item("Ctrl").Value = Nz(oProgress.Item("Ctrl").Value, "") & oProgress.Item("Msg").Item(oProgress.Item("Msg").Count) & vbCrLf
    
    ' Move cursor
    oProgress.Item("Ctrl").SelStart = Len(oProgress.Item("Ctrl").Value)
    
    ' Hide message window if required
    If bHide And oProgress.Item("Hide") Then
        Forms(oProgress.Item("Frm")).Visible = False
    End If
    
    ' Ensure screen is refreshed
    DoEvents
    
    Exit Sub

EH_ShowProgressMsg:
    MsgBox "Error shwoing message : " & Err.Source & " - " & Err.Description & " - " & Err.Number
    
End Sub

This first time I use the email object everything is fine, the email works, the progress windows shows the steps, everything is dandy.

However, if I re initialise the same object to send a second email..

EG...
Code:
Dim oEmail as New clsEMailWrapperII

oEmail.Subject = "Hello World"
oEmail.To = "me@mydomain.com"
oEmail.Body = "This is an email"
oEmail.Create
oEmail.Send

' HERE IS WHEN I REUSE THE OBJECT
Set oEmail = new clsEmailWrapperII
oEmail.Subject = "Hello World Again"
oEmail.To = "me@mydomain.com"
oEmail.Body = "This is another email"

' THIS IS WHEN IT ERRORS....
oEmail.Create

The error is actually happening in the show progress method on this line...
Code:
    ' Update message window
    oProgress.Item("Ctrl").Value = Nz(oProgress.Item("Ctrl").Value, "") & oProgress.Item("Msg").Item(oProgress.Item("Msg").Count) & vbCrLf

Why? the form opens like it usually should but the control is blank and the class crashes when trying to update with the progress message, yet it works fine first time round.

So how come the code works first time but not second time?

Thanks,
1DMF


"In complete darkness we are all the same, it is only our knowledge and wisdom that separates us, don't let your eyes deceive you."

"If a shortcut was meant to be easy, it wouldn't be a shortcut, it would be the way!"
Free Electronic Dance Music
 
Have you tried setting oProgress = Nothing between instantiations?

Beir bua agus beannacht!
 
I would have thought that re-instantiating (Class_Initialize) would reset the scripting object referenced by oProgress

However, I tried putting your code in the Class_Terminate and still no joy.

Interestingly though I ran this test...

Code:
    Dim oE1 As New clsEmailWrapperII
    
    oE1.Subject = "test"
    oE1.AddTO ("craig@mydomain.com")
    
    oE1.Body = "this is a test"
    oE1.Create
    oE1.Send

    Set oE1 = New clsEmailWrapperII
    
    oE1.Subject = "test2"
    oE1.AddTO ("craig@mydomain.com")
    oE1.Body = "this is another test"
    oE1.Create
    oE1.Send
    Set oE1 = Nothing
I'm not getting the error, but the second email isn't being sent and the progress window on the second email shows, but remains blank (no progress information).

So I made this alteration....
Code:
    Dim oE1 As New clsEmailWrapperII
    
    oE1.Subject = "test"
    oE1.AddTO ("craig@mydomain.com")
    
    oE1.Body = "this is a test"
    oE1.Create
    oE1.Send

    [highlight #FCE94F]Set oE1 = Nothing[/highlight]       

    Set oE1 = New clsEmailWrapperII
    
    oE1.Subject = "test2"
    oE1.AddTO ("craig@mydomain.com")
    oE1.Body = "this is another test"
    oE1.Create
    oE1.Send
    Set oE1 = Nothing

And it worked perfectly, the progress window information showed on both occasions and both emails got sent.

I've come to the conclusion it has something to do with garbage collection and potentially old references hanging around or the way objects are instantiated, because all I had to do was set the var reference to nothing before re-using it and it worked perfectly, yet re-instantiating an object on an existing reference variable is not killing the previous object?

Perhaps someone can explain why this is the case.






"In complete darkness we are all the same, it is only our knowledge and wisdom that separates us, don't let your eyes deceive you."

"If a shortcut was meant to be easy, it wouldn't be a shortcut, it would be the way!"
Free Electronic Dance Music
 
> garbage collection

Just a quick minor point of order: COM (and VBA) do not do garbage collection.
 
Objects clean themselves up. That's what reference counts are all about.
 
If you set an existing reference var to a new object, why doesn't clear the old object?

I'm assuming this is semantics, garbage, rubbish, clean themselves, same thing = free up the memory that was used by an object so it can be used for something else as it is no longer required.

How comes
Code:
Dim obj As Object
Set obj = New clsMyClass 
Set obj = New clsMyClass
cause problems

yet
Code:
Dim obj As Object
Set obj = New clsMyClass 
Set obj = Nothing
Set obj = New clsMyClass

Doesn't?

obj no longer references the first instantiation of the object when a new one is created (or at least it shouldn't?), so is a different reference, yet you seem to have to set it to nothing before you can reuse the variable.

Why and is this only if you reinstantiate the same object class type it was originally referencing.

What's the 'Nothing' doing that 'New' isn't?




"In complete darkness we are all the same, it is only our knowledge and wisdom that separates us, don't let your eyes deceive you."

"If a shortcut was meant to be easy, it wouldn't be a shortcut, it would be the way!"
Free Electronic Dance Music
 
>I'm assuming this is semantics

Well if you want apply the term "garbage collection" to a system that has no collector and no garbage, then feel free :)

>How comes

Code:
Dim obj As Object
Set obj = New clsMyClass 
Set obj = New clsMyClass

Well, that's not quite what you are doing, you are doing:

Code:
Dim obj As New Object
Set obj = New clsMyClass 
Set obj = New clsMyClass

which is subtly (but in this case probably not importantly) different.

OK, so when you do

Set obj = New clsMyClass

that increments the reference counter for an instance of clsMyCLass (and runs the initialise event if this is the first reference to the object) that obj points to and decrements the reference count of any object instance that it was previously referring to (if any). The order of these events may be important if you are relying on clean up code in the terminate event to have been run before the new instance is initialized.

Decrementing a reference count does not destroy the instance (so ignore any articles that say that setting an object to Nothin will destroy it; it doesn't) It is only destroyed - and consequently runs the terminate event - when the reference count becomes 0.

So, from an event point of view your first example does (assuming we are not adding any other references to the objects):

Initialize (first instance of class)
Initialize (second instance of class)
Terminate (first instance of class)
And, assuming we go out of scope
Terminate (second instance of class)

whilst your second example does:

Initialize (first instance of class)
Terminate (first instance of class)
Initialize (second instance of class)
And, assuming we go out of scope
Terminate (second instance of class)





 
>> Well if you want apply the term "garbage collection" to a system that has no collector and no garbage, then feel free smile

Yeah, ok, you know what I mean, and since when were unwanted memory allocations not garbage? [tongue]

Code:
Private Sub Class_Terminate()

On Error Resume Next
    
    Call AddProgress("Email processing complete.")
    
    ' Close progress window
    If oProgress.Item("Close") Then
        [highlight #FCE94F]DoCmd.Close acForm, oProgress.Item("Frm")[/highlight]
    End If
    

End Sub

Seriously though, thank you Mike , I finally worked out the problem!

As you say intialise was running twice then the terminate, the terminate was closing the form then when the progress window was trying to be updated, the code found the form closed, so opens it, but the hook into the text box control for displaying the messages had been lost!

Hence the application defined error.

I have refactored my class, so if the form is closed, it runs InitProgress again, which has been slightly altered...

Code:
' Initialise progress window
Public Sub InitProgress(ByVal sFormName As String, ByVal sTextCtrl As String, ByVal bHide As Boolean, ByVal bClose As Boolean, Optional ByVal sSubFormName As String = "")

'On Error Resume Next

    Dim cTextBox As Access.TextBox
    
    ' Open form if not open
    If Not CurrentProject.AllForms(sFormName).IsLoaded Then
        DoCmd.OpenForm sFormName, acNormal
    End If
    
    ' Hide form
    If bHide Then
        Forms(sFormName).Visible = False
    End If
    
    ' Set textbox control
    If sSubFormName <> "" Then
        Set cTextBox = Forms(sFormName).Controls(sSubFormName).Form.Controls(sTextCtrl)
    Else
        Set cTextBox = Forms(sFormName).Controls(sTextCtrl)
    End If
       
[highlight #FCE94F]    ' Set progress vars
    Set oProgress = Nothing
    Set oProgress = CreateObject("Scripting.Dictionary")
    oProgress.Add "Frm", sFormName
    oProgress.Add "Sub", sSubFormName
    oProgress.Add "Txt", sTextCtrl
    oProgress.Add "Ctrl", cTextBox
    oProgress.Add "Close", bClose
    oProgress.Add "Hide", bHide
    oProgress.Add "Msg", cProgressMsg[/highlight]
    
End Sub

And so in the ShowProgress method, instead of just opening the form it re-initilaises it from itself...
Code:
    ' Check if form open
    If Not CurrentProject.AllForms(oProgress.Item("Frm")).IsLoaded Then
        ' initialise form again
        [highlight #FCE94F]Call InitProgress(oProgress.Item("Frm"), oProgress.Item("Txt"), oProgress.Item("Hide"), oProgress.Item("Close"), oProgress.Item("Sub"))[/highlight]
    End If

Now it is working correctly without the need to set it to Nothing before reusing the object.

Wow, that was a needle in a haystack, thank you for being an electromagnet!



"In complete darkness we are all the same, it is only our knowledge and wisdom that separates us, don't let your eyes deceive you."

"If a shortcut was meant to be easy, it wouldn't be a shortcut, it would be the way!"
Free Electronic Dance Music
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top