Re: owner of class

Tech-Archive recommends: Repair Windows Errors & Optimize Windows Performance

From: Mike D Sutton (EDais_at_mvps.org)
Date: 12/30/04


Date: Thu, 30 Dec 2004 19:43:19 -0000


> I have an application where I use a lot of class modules. At least a
> hundred, and some of these
>
> Something that I think would help me during debugging is to know what class
> objects are currently initialized, what intanciated them (i.e. myclass1
> created an instance of myclassX and myclass2 created an instance of myclassX.)
>
> One way I was thinking of doing it was to include a variable or two in each
> class module that gets set when the class is created that contains the
> specific name of the class (i.e. cAcct might be set goodAcct = new cAcct and
> set baddAcct = new cAcct). Then, add a set of AddToStack/RemoveFromStack
> functions to each class that would maintain an inventory of existing class
> objects.
>
> What I want to accomplish is to identify possible situations where I
> terminate a given object but because I've created circular reference, the
> class doesn't terminate until after I terminate one or more other classes.
>
> What I would like to be able to do is have a hidden interface 'feature' that
> would display a list of all of the active classes and who called them. Then,
> I could easily tell of a class was still active after I thought it should be
> closed.
>
> Example:
>
> Module/Class/Form Instance Name Class
> ===========================
> frmMain goodAcct cAcct
> frmMain badAcct cAcct
> frmMain strClass cString
> myClass strClass cString
>
> I don't suppose there is anyway to ask the application itself (i.e. is there
> some sort of reachable collection of active classes already) without needing
> me to create and manage my own?

One way of doing this is to have an Attach and Detach method of each class that allows it to store it's parent object, probably the
easiest way of doing this is you have multiple classes in your project is to use an interface which exposes the functionality:

'*** IParentTrack
Public Property Get ParentObj() As Object
End Property

Public Sub AttachParent(ByRef inParent As Object)
End Sub

Public Function DetachParent() As Boolean
End Function
'***

Then each class you need to know it's parent object can simply implement the interface:

'***
Implements IParentTrack

Dim m_ParentObj As Object

Private Property Get IParentTrack_ParentObj() As Object
    Set IParentTrack_ParentObj = m_ParentObj
End Property

Private Sub IParentTrack_AttachParent(ByRef inParent As Object)
    m_ParentObj = inParent
End Sub

Private Function IParentTrack_DetachParent() As Boolean
    IParentTrack_DetachParent = Not (m_ParentObj Is Nothing)
    m_ParentObj = Nothing
End Function
'***

You must remember to call DetachParent() on each before you want to destroy it though otherwise you're left with a circular
reference. If you don't like this solution then you could store a 'soft pointer' to the parent by using the ObjPtr() function
instead:

'*** IParentTrack
Public Property Get ParentPtr() As Long
End Property

Public Sub AttachParent(ByRef inParent As Object)
End Sub

Public Function DetachParent() As Boolean
End Function
'***

'***
Implements IParentTrack

Dim m_ParentPtr As Long

Private Property Get IParentTrack_ParentPtr() As Long
    IParentTrack_ParentPtr = m_ParentPtr
End Property

Private Sub IParentTrack_AttachParent(ByRef inParent As Object)
    m_ParentObj = ObjPtr(inParent)
End Sub

Private Function IParentTrack_DetachParent() As Boolean
    IParentTrack_DetachParent = (m_ParentPtr <> 0)
    m_ParentObj = 0
End Function
'***

This doesn't quite give you the flexibility of the first solution, but doesn't create any circular references. If you need to get
back to the parent object from the pointer then you can use this function:

'***
Private Declare Sub PutDWord Lib "MSVBVM60.dll" Alias _
    "PutMem4" (ByRef inDst As Any, ByVal inSrc As Long)

...

Private Function ResolveObjPtr(ByVal inPtr As Long) As Object
    Dim TempObj As Object

    If (inPtr) Then
        Call PutDWord(TempObj, inPtr)
        Set ResolveObjPtr = TempObj
        Call PutDWord(TempObj, 0&)
    End If
End Function
'***

If the parent object has already been released though, this will give you back an invalid object which will more thank likely kill
the IDE if you attempt to use it, so be careful when using it..
If you're in a position to use a class factory for your object creating then it's possible to add parent/child relationships
directly into it including communication between the parent and child classes for when either gets destroyed - Have a look at the
class factory and subject/observer design patterns if you want to know more on this approach.
Hope this helps,

    Mike

 - Microsoft Visual Basic MVP -
E-Mail: EDais@mvps.org
WWW: http://EDais.mvps.org/



Relevant Pages

  • Re: Sorting a System.Collections.ObjectModel.Collection
    ... Public Sub Dispose() Implements System.IDisposable.Dispose ... Private m_SupportsSorting As Boolean = True ... Protected Overrides ReadOnly Property SupportsSortingCoreAs Boolean ... Dim m_SortList As New ArrayList ...
    (microsoft.public.dotnet.languages.vb)
  • Re: Sorting a System.Collections.ObjectModel.Collection
    ... Public Sub Dispose() Implements System.IDisposable.Dispose ... Private m_SupportsSorting As Boolean = True ... Protected Overrides ReadOnly Property SupportsSortingCoreAs Boolean ... Dim m_SortList As New ArrayList ...
    (microsoft.public.dotnet.languages.vb)
  • Re: owner of class
    ... >> terminate a given object but because I've created circular reference, ... > Public Sub AttachParent ... > Then each class you need to know it's parent object can simply implement ... > Private Sub IParentTrack_AttachParent ...
    (microsoft.public.vb.general.discussion)
  • Re: Internet Explorer steuern per VBA
    ... Private WithEvents mobjIE As InternetExplorer ... Private mblnSichtbar As Boolean ... Private mblnComplete As Boolean ... Private Sub Class_Initialize ...
    (microsoft.public.de.excel)
  • Bind a class to Property Grid - No setter executed
    ... Set(ByVal value As LineSetting) ... Private m_DisplayGrid As Boolean = True ... Public Sub New ...
    (microsoft.public.dotnet.languages.vb)