Library tutorials & articles
Circular Referencing to COM Objects
- Introduction
- Why Avoid the Reference Count?
- How to Soft Reference an Object
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"
Related articles
Related discussion
-
VB6 Runtime error 381 subsript out of range Error
by Uncle (2 replies)
-
passing and reading parameters from using Shell
by jigartoliya (0 replies)
-
Convert C++ code to VB6
by mawcot (4 replies)
-
listbox scrollbar
by Dennijr (10 replies)
-
Can you describe Above simple VB6 code?
by pramodmca09 (0 replies)
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...
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:
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.
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.
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
This thread is for discussions of Circular Referencing to COM Objects.