Library tutorials & articles

Circular Referencing to COM Objects

Why Avoid the Reference Count?

Well, under normal circumstances, you should not avoid it. But, there are some cases where this is actually useful. The most obvious of all is a Parent property in a COM object. A Parent property is a circular reference that causes the parent object to stay in memory even when required to unload, that is, if you are not careful.

Let us pose an example: Any VB control (yes, I know, not very specific; make that a textbox then). They all have a Parent property that returns a reference to the form where they reside.

You can test the parent property by using the following code. Just create a new VB project, add a textbox called Text1, and add the presented code into the click event of a Command button.

Dim myForm as Form

set myForm = Text1.Parent
Debug.Print myForm.Caption

Well, lets now complicate things a bit. Imagine you would like to create a control similar to a ListView control. As you probably know, ListViews provide access to its elements in the form of ListItem objects. This item objects can return its parent, just like the textbox in the example above.

NOTE: I will not be presenting full coding (take the collection declaration as an example) because it is not the purpose of this article to show you how to, for example, create a collection class. If you want to learn how to create one, I suggest you play with the Class Builder Add-in for Visual Basic. The same goes for similar subjects.

So you start creating your control named SuperListBox, and in the process, you add a class module and call it SuperListItem. Then, you add a property called "Parent", and you code it like this:

Option Explicit

'Private instance of the parent
Private mvarParent as SuperListBox

'Now you add the property code
Public Property Get Parent() as SuperListBox
    Set Parent = mvarParent
End Property

'You make the Set part of the property a Friend procedure,
'just to make sure the end programmer will not mess with it
Friend Property Set Parent(ByVal oNewParent as SuperListBox)
    mvarParent = oNewParent
End Property

Nice. The parent property is done. Also, you decide to create a collection class, called SuperListItems to hold all the items being created. Sounds good to me. Furthermore, whenever you create a new SuperListItem object, you'll be setting its Parent property before any other code and before returning the object to the host program, and you will also be adding the new list item to the collection. Simple:

Dim oNewItem as SuperListItem

Set oNewItem = New SuperListItem
Set oNewItem.Parent = Me
oMyCollection.Add oNewItem

Finally, you, as good fellow who likes to do things by the book, add to the Terminate event the following lines, to be sure you are cleaning up your mess:

Private Sub Usercontrol_Terminate()
    Set oMyCollection = Nothing
End Sub

Just to demonstrate my point here, add the line Debug.Print "Terminating" in the Usercontrol_Terminate event.

Good. Now everything is set. You test your control by creating, in a standard project, a few list items and such. Then finish the program and check the debug window. You will NOT find the "Terminating" message that we were expecting!! Why??? I already explained that. The COM object instance of your control is still referenced! Its reference count is not zero. There is one reference per ListItem to the instance of your usercontrol. But why this happens if you added the cleanup code and all!!?? Well, the cleanup code never runs because the object never starts its own destruction in the first place.

"But I really need the Parent Property in place!!", you say. I know that. Turn the page to learn the solution: Soft referencing"

Comments

  1. 21 Feb 2003 at 03:52
    Great tutorial.This will definitely change the way i look up on these Matters..
  2. 09 Feb 2003 at 05:05

    There is no secret as to how you decrease the reference count of a COM object.  All you have to do is call the Release method of the IUnknown interface.  But VB will hide this.  However, you can cheat by creating or using a type library that does define the IUknown interface.  Then you could just do something like this:

    Code:
    Private Sub UserControl_Initialize()


    dim oObject as IUnknown


      Set Splitter1.LeftCtl = LeftThing
      Set Splitter1.RightCtl = RightThing


      set oObject = LeftThing
      oObject.Release
      set oObject = Nothing
      set oObject = RightThing
      oObject.Release
      set oObject = Nothing
    End Sub


    That should take care of it.  However, this method is somewhat cumbersome and can be easily avoided by soft referencing.  I say go with soft referencing.

  3. 20 Jan 2003 at 12:06

    I have a project with Splitter controls that require references to pairs of controls that are proportionally resized by the user.
    The application GPF's (occasionally) upon termination. If run inside a browser, it causes an error report and the browser stays in memory.
    I realize that setting the controls reference to Nothing during the Usercontrol_Terminate event would solve the problem, but your article explains why this was not happening. So that is good.
    Your solution is intriguing, but I would like to ask you if another solution might work.
    How about we reduce the refrence count on the objects in the Initialize routine? Like this:


    Private Sub UserControl_Initialize()
       Set Splitter1.LeftCtl = LeftThing
       Set Splitter1.RightCtl = RightThing


       ReduceRefrenceCountByOne LeftThing
       ReduceRefrenceCountByOne RightThing
    End Sub


    Now the Controls will be come out of memory as we really want when the parent control terminates. Incidentally, their UserControl_Terminate events will fire correctly too.


    Perhaps you have written the code to do the evil reference count manipulation?


    What do you think?


    G.

  4. 20 Dec 2002 at 12:50
    Glad it helped.
  5. 10 Dec 2002 at 06:47

    I struggled for a long time with my app hanging after it quits.  It turned out to be a circular reference in the (approximately) 180 000 objects.


    Thnx for the great explanation and work-around.  Everything going smoothly again.


    igitur

  6. 10 Oct 2002 at 17:44
    very interesting and usefull trick. (I should have thought about it myself)
  7. 01 Jan 1999 at 00:00

    This thread is for discussions of Circular Referencing to COM Objects.

Leave a comment

Sign in or Join us (it's free).

Jose Pablo Ramirez Vargas

Related discussion

Related podcasts

  • Christian Beauclair

    14 mai 2008 (�mission #0074) ::.Christian Beauclair: Stratégies de migration VB6 vers .NET Nous discutons avec Christian Beauclair des stratégies de migration VB6 vers .NET. Entre autres, nous discutons comment utiliser le "VB 6 Code Advisor" et le "Interop Forms Toolkit" pour ajouter la puiss...

We'd love to hear what you think! Submit ideas or give us feedback