Home All Groups Group Topic Archive Search About
Author
8 Aug 2010 11:58 PM
BeeJ
I have some ActiveX code, both EXE and DLL that I wrote.
It all seems to work but I occasionally have a weird thing happen.
The code runs through Class_Terminate before Class_Initialize.
I do not see why but it may be because I am working in the IDE and
maybe this app is not closing as I thought or does the Set cEntry = Me
make a double instantiation?
There is no Main module and this does not start, Class_Initialize,
until the app is instantiated in the main program.
This is one of the ActiveX that do not want to terminate.  All the
others do what they are supposed to.

The entry class named 'Entry' has this:
' =================================================
Public Event DevStatus(sStatus As String)

Private Sub Class_Initialize()
    Set cEntry = Me              ' to allow access from
                                 ' modules back to this class
    Startup                      ' code in module
End Sub 'Class_Initialize

Private Sub Class_Terminate()
    On Error GoTo Class_TerminateErr
    ShutDown                      ' code in module
    Set cEntry = Nothing
Class_TerminateExit:
    Exit Sub
Class_TerminateErr:
    Debug.Assert False
    Resume Class_TerminateExit
End Sub 'Class_Terminate

Friend Sub StatusMsg(sMsg As String)
    RaiseEvent DevStatus(sMsg)
End Sub 'StatusMsg

' =================================================

The module mdlEntry has this:
' =================================================
Public cEntry As Entry

Private Sub Msg(sMsg as String)
    cEntry.StatusMsg sMsg
End Sub
' =================================================

Author
9 Aug 2010 1:29 AM
ralph
On Sun, 08 Aug 2010 16:58:38 -0700, BeeJ <nospam@nowhere.com> wrote:

>I have some ActiveX code, both EXE and DLL that I wrote.
>It all seems to work but I occasionally have a weird thing happen.
>The code runs through Class_Terminate before Class_Initialize.
>I do not see why but it may be because I am working in the IDE and
>maybe this app is not closing as I thought or does the Set cEntry = Me
>make a double instantiation?

Not a double instantiation - but does call Terminate.

The Initialize event is fired only once when the object is created.
Re-assigning to new references doesn't fire the event.

However, the Terminate event is fired when the object is set to
Nothing, when the last referenced object is 're-set' to a new
reference using the Set/New, or when it is re-assigned to a new
instance.

-ralph
Author
9 Aug 2010 2:22 AM
Tom Shelton
ralph pretended :
> On Sun, 08 Aug 2010 16:58:38 -0700, BeeJ <nospam@nowhere.com> wrote:
>
>> I have some ActiveX code, both EXE and DLL that I wrote.
>> It all seems to work but I occasionally have a weird thing happen.
>> The code runs through Class_Terminate before Class_Initialize.
>> I do not see why but it may be because I am working in the IDE and
>> maybe this app is not closing as I thought or does the Set cEntry = Me
>> make a double instantiation?
>
>

<snip>

>
> However, the Terminate event is fired when the object is set to
> Nothing, when the last referenced object is 're-set' to a new
> reference using the Set/New, or when it is re-assigned to a new
> instance.

I think your trying to say that the terminate event fires when the last
reference is released - correct?

Just to be clear - doing a Set cEntry = Me would cause the reference
count of the object pointed to by me to be incremented by one.  And
then when cEntry went out of scope, the reference count would be
reduced by one - but, the terminate event would not fire...  Since the
Me reference is still arround.

One cause of the described behavior maybe a circular reference.... 
That can definately cause a memory leak and an exe to hang around in
memory rather then shutdown properly.  Hard to know without seeing some
code though....

--
Tom Shelton
Author
9 Aug 2010 4:17 PM
BeeJ
Tom Shelton expressed precisely :
Show quoteHide quote
> ralph pretended :
>> On Sun, 08 Aug 2010 16:58:38 -0700, BeeJ <nospam@nowhere.com> wrote:
>>
>>> I have some ActiveX code, both EXE and DLL that I wrote.
>>> It all seems to work but I occasionally have a weird thing happen.
>>> The code runs through Class_Terminate before Class_Initialize.
>>> I do not see why but it may be because I am working in the IDE and maybe
>>> this app is not closing as I thought or does the Set cEntry = Me make a
>>> double instantiation?
>>
>>
>
> <snip>
>
>>
>> However, the Terminate event is fired when the object is set to
>> Nothing, when the last referenced object is 're-set' to a new
>> reference using the Set/New, or when it is re-assigned to a new
>> instance.
>
> I think your trying to say that the terminate event fires when the last
> reference is released - correct?
>
> Just to be clear - doing a Set cEntry = Me would cause the reference count of
> the object pointed to by me to be incremented by one.  And then when cEntry
> went out of scope, the reference count would be reduced by one - but, the
> terminate event would not fire...  Since the Me reference is still arround.
>
> One cause of the described behavior maybe a circular reference....  That can
> definately cause a memory leak and an exe to hang around in memory rather
> then shutdown properly.  Hard to know without seeing some code though....

On exiting, in  Class_Terminate I do

  Set cEntry = Nothing

So that should decrement.
Author
10 Aug 2010 9:51 AM
Dee Earley
On 09/08/2010 17:17, BeeJ wrote:
> On exiting, in Class_Terminate I do
>
> Set cEntry = Nothing
>
> So that should decrement.

It will never decrement as cEntry still has a reference to it so the
Terminate event will never be called.

You must have an explicit "Close" method that unsets cEntry and allows
it to terminate.

--
Dee Earley (dee.ear***@icode.co.uk)
i-Catcher Development Team

iCode Systems

(Replies direct to my email address will be ignored.
Please reply to the group.)
Author
10 Aug 2010 12:27 PM
Larry Serflaten
"BeeJ" <nospam@live.com> wrote

> On exiting, in  Class_Terminate I do
>
>   Set cEntry = Nothing
>
> So that should decrement.


I would think not.  The class that is terminating is cEntry.
In order for cEntry to terminate, all references to it have
to be realeased.

My point is, that at that point in time, cEntry should essentially
already be Nothing, so setting it to Nothing again, has no effect.

You did not show your class instantiation in your first post.
Where are you creating the first instance of that class?

LFS
Author
10 Aug 2010 2:51 PM
BeeJ
I use this in several places.

Case 1:  the main form instantiates this.

    Dim cEntry as Entry        ' e.g. within a sub

    Set cEntry = New Entry     '

Case 2:  the main app instantiates an ActiveX EXE using early binding.

    Private WithEvents cEntry as Ax.Entry

    Set cEntry = New Ax.Entry


Now I am working with Case 2.
Author
10 Aug 2010 4:39 PM
ralph
On Tue, 10 Aug 2010 07:51:30 -0700, BeeJ <nospam@live.com> wrote:

Show quoteHide quote
>I use this in several places.
>
>Case 1:  the main form instantiates this.
>
>    Dim cEntry as Entry        ' e.g. within a sub
>
>    Set cEntry = New Entry     '
>
>Case 2:  the main app instantiates an ActiveX EXE using early binding.
>
>    Private WithEvents cEntry as Ax.Entry
>
>    Set cEntry = New Ax.Entry
>
>
>Now I am working with Case 2.
>

Abandon 'thought experiments'.

Create a simple test suite, one client exe, one ActiveX exe. With one
object - MyClass.
Add a message/logger to the Initialize and Terminate events in
MyClass. It is also helpful to provide a static 'count'.
Duplicate the same basic calling/creating/destruction architecture,
but leave out the rest of the code.
(The VB Class Builder is very useful for generating this MyClass
object with 'debug' code.)
Then run it with both projects open and watch the sequence of events.
You are bound to be surprised.

You may need to move to a Proxy or Mediator pattern.

-ralph
Author
10 Aug 2010 8:59 PM
Larry Serflaten
"BeeJ" <nospam@live.com> wrote

> I use this in several places.
>
> Case 1:  the main form instantiates this.
>
>     Dim cEntry as Entry        ' e.g. within a sub
>
>     Set cEntry = New Entry     '

Then, every time you call up a 'new' copy, the first thing it does
is this:

Private Sub Class_Initialize()
    Set cEntry = Me              ' to allow access from
                                 ' modules back to this class
    Startup                      ' code in module
End Sub 'Class_Initialize

Which in effect wipes out the old instance in favor of the new.
Try this instead:

In the module (mdlEntry) where you have:

Public cEntry As Entry

Private Sub Msg(sMsg as String)
    cEntry.StatusMsg sMsg
End Sub

Use this:

'============
Private mEntry As Entry

Private Sub Msg(sMsg as String)
    cEntry.StatusMsg sMsg
End Sub

Public Property Get cEntry() As Entry
  If mEntry Is Nothing then Set mEntry = New Entry
  Set cEntry = mEntry
End Property

Public Sub CleanUp()
  Set mEntry = Nothing
End Sub
'================

Then, you'll never need to create an instance, and you will
be gaurenteed to be be using only one instance.  When its
time to close down, call the CleanUp routine to release that
one copy of Entry.


LFS








Show quoteHide quote
>
> Case 2:  the main app instantiates an ActiveX EXE using early binding.
>
>     Private WithEvents cEntry as Ax.Entry
>
>     Set cEntry = New Ax.Entry
>
>
> Now I am working with Case 2.
>
>
Author
10 Aug 2010 9:53 PM
BeeJ
Thanks.  That is very different and I will give it a try.