A rogue reference count example

Let’s look at the EdII program proposed early in Chapter 9. The example used throughout the chapter was a text editor called Edwina. EdII (Edwina II) was a proposed multiple document interface (MDI) enhancement to Edwina. EdII would have an XEditor control on each child form. When a child form was closed, its XEditor control would be destroyed, but EdII would keep running. The situation I’m about to describe applies to EdII because it happens only when the component goes away but the program continues.

Imagine that a user of EdII opens a child window. That window creates an instance of XEditor with a reference count of 1. Next the user selects Find from the Search menu and an FSearch form appears. The FSearch form needs a reference to the same XEditor instance so that it can pass search requests back to the editor. The XEditor instance now has a reference count of two. The XEditor instance created the FSearch form and keeps the only reference to it, but since the FSearch form is modal, it operates independently of its creator, the XEditor instance.

Now assume the user clicks the Close button on the FSearch form and the form unloads itself. The XEditor’s reference is decremented and, since the form now has a reference count of zero, COM destroys it. Everything is fine.

But what if the user closes the MDI child window instead of the FSearch form? COM calls the Release method to destroy the child window’s XEditor instance, but since the FSearch form still has an outstanding reference to the XEditor control, the reference count will not reach 0, the control will not be destroyed, and the Terminate event will not be called. The FSearch form and its XEditor instance will live on, using resources even though the form that was supposed to control it has disappeared. The FSearch form is like Frankenstein’s monster—independent and out of control. The user sees the form, but not the editor being searched. Technically, this problem also occurs in Edwina, but because Edwina terminates at the same time that the XEditor instance is destroyed, Visual Basic automatically kills the rogue search form.

Since the XEditor instance creates the search form, we’d like XEditor to own FSearch and be able to terminate it. The lifetime of the search form should be bounded by the lifetime of XEditor. But there’s no way for XEditor to know when it’s being destroyed because the FSearch reference to XEditor keeps the Terminate event from being fired.

If we were writing XEditor and FSearch in C++ or B--, this would be a simple problem. Don’t call AddRef and Release on the FSearch reference to XEditor. The XEditor on FSearch is actually owned by the creating XEditor, so there’s no need for it to have a separate reference count. XEditor will destroy this form when it’s ready. With this fix, the reference count of XEditor will be 1, not 2, and when the child window tries to destroy XEditor, the count will go to 0, the control will be destroyed, and XEditor’s Terminate event can unload FSearch and set its reference variable to Nothing. Everything comes out right. Of course, we don’t really want to manage all reference counting just to avoid this problem. We want a way to handle the problem in Visual Basic.