INTELLIGENT WORK FORUMS
FOR COMPUTER PROFESSIONALS

Log In

Come Join Us!

Are you a
Computer / IT professional?
Join Tek-Tips Forums!
  • Talk With Other Members
  • Be Notified Of Responses
    To Your Posts
  • Keyword Search
  • One-Click Access To Your
    Favorite Forums
  • Automated Signatures
    On Your Posts
  • Best Of All, It's Free!

*Tek-Tips's functionality depends on members receiving e-mail. By joining you are opting in to receive e-mail.

Posting Guidelines

Promoting, selling, recruiting, coursework and thesis posting is forbidden.

Jobs

Application-defined or object-defined error

Application-defined or object-defined error

(OP)
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

RE: Application-defined or object-defined error

Have you tried setting oProgress = Nothing between instantiations?

Beir bua agus beannacht!

RE: Application-defined or object-defined error

(OP)
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

    Set oE1 = Nothing       

    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

RE: Application-defined or object-defined error

> garbage collection

Just a quick minor point of order: COM (and VBA) do not do garbage collection.

RE: Application-defined or object-defined error

Objects clean themselves up. That's what reference counts are all about.

RE: Application-defined or object-defined error

(OP)
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

RE: Application-defined or object-defined error

>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 smile

>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)





RE: Application-defined or object-defined error

So, what is cProgressMsg?

RE: Application-defined or object-defined error

(OP)
>> 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
        DoCmd.Close acForm, oProgress.Item("Frm")
    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
       
    ' 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
    
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
        Call InitProgress(oProgress.Item("Frm"), oProgress.Item("Txt"), oProgress.Item("Hide"), oProgress.Item("Close"), oProgress.Item("Sub"))
    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

RE: Application-defined or object-defined error

Glad you got it sorted

Red Flag This Post

Please let us know here why this post is inappropriate. Reasons such as off-topic, duplicates, flames, illegal, vulgar, or students posting their homework.

Red Flag Submitted

Thank you for helping keep Tek-Tips Forums free from inappropriate posts.
The Tek-Tips staff will check this out and take appropriate action.

Reply To This Thread

Posting in the Tek-Tips forums is a member-only feature.

Click Here to join Tek-Tips and talk with other members!

Resources

Close Box

Join Tek-Tips® Today!

Join your peers on the Internet's largest technical computer professional community.
It's easy to join and it's free.

Here's Why Members Love Tek-Tips Forums:

Register now while it's still free!

Already a member? Close this window and log in.

Join Us             Close