循环引用和部件的关闭

下面说明 Visual Basic 是如何卸载进程内部件的。当客户应用程序释放了对一个进程内部件的对象的所有引用后,该部件将被卸载。另外,还说明循环引用将如何妨碍这种卸载,强调指出公有和私有对象的重要区别。

因为Visual Basic从不会卸载一个在开发环境中运行的进程内部件工程,所以,上述过程只能使用编译过的部件和编译过的测试工程来进行。

注意 创建一个 ActiveX DLL 示例需要分为几步,这个帮助主题只是其中一步。要访问该帮助主题,选择帮助主题“创建 ActiveX DLL”即可。

要观察 DLL 的卸载,请按照以下步骤执行:

  1. 向 ThingDemo 中添加新的类模块。将其命名为 TellTale,并把它的 Instancing 属性设为 Private。向它的 Terminate 事件中添加下列代码:
    Private Sub Class_Terminate()
    MsgBox "Private object destroyed"
    End Sub
    

    私有的对象不能由客户应用程序创建,并且永远不会传递给它们。可以看到,私有的对象并不阻止进程内部件的卸载。在部件卸载后,如果客户应用程序仍然使用对一个私有对象的引用,那么将会导致严重的程序错误。

  2. 向 ThingDemo 中的模块 Module1 添加下列代码:
    Option Explicit
    Private mtt As TellTale        '新代码。
    
    Sub Main
    Debug.Print "E xecuting Sub Main"
    Set mtt = New TellTale        '新代码。
    End Sub
    

    一旦编译了工程之后,就不能再使用 Debug 语句来显示内部发生的情况。就象一个告密者一样,TellTale 对象的作用是显示编译的部件内发生了什么情况。

  3. 在“文件”菜单中,单击“生成工程组”编译 ThingDemo 和 ThingTest。在“启动”菜单中,单击“运行”打开“运行”对话框,通过浏览找到并运行 ThingTest,也可以使用 Windows 资源管理器。

  4. 关闭模式对话框,并单击“Create Temporary Thing”。在输入框中随意输入一个名字,然后单击“确定”。

    正如前面看到的,临时的 Thing 并不会存在很长时间。现在创建它的原因只是为了加载 ThingDemo.dll 并执行 Sub Main。对于目前的步骤,一个很有意思的问题是:如果 Thing 全部没有了的话,那么情况会是什么样?

  5. 等一会儿,喝杯咖啡或是干点别的什么。等过几分钟后再回来看时,就会看见一个消息框,上面的消息是“Private object destroyed”。

    究竟是怎么回事?由于没有对公共对象的引用,在一段时间后(通常是两分钟左右,不过也依赖于程序进入空闲状态的时间间隔),Visual Basic 将试图卸载进程内部件。

    在卸载 DLL 时,Visual Basic 将释放它使用的内存,其中也包含了含有私有对象引用的变量。结果 TellTale 对象就被破坏了,这个线索可以告诉我们 DLL 被卸载。

    如果此时创建新的 Thing 对象,那么在 DLL 被重新载入时可以发现一小段的暂停。

  6. 现在来演示循环引用。选中“Stuck on itself”框,然后单击“Create Temporary Thing”,创建一个自己引用自己的 Thing 对象。

  7. 等一会儿,再喝杯咖啡或干点别的什么。不过无论等多长时间,DLL 都不会被卸载,因为对 Thing 对象的引用阻止了 Visual Basic 卸载它。

    Visual Basic 不能区分对公共变量的内部引用和对公共对象的外部(客户应用程序)引用,因此它不会卸载 DLL。

  8. 关闭 ThingTest 的主窗体。私有变量再次被破坏,因为在卸载客户应用程序的同时要卸载用到的所有进程内部件。

详细信息 关于关闭部件的规则,请参阅“部件设计的一般准则”的“启动和结束部件”的列表,附录 A“ActiveX 部件标准及指南”中有更详细的讨论。

循序渐进

创建 ActiveX DLL 示例需要好几步,该帮助主题只是其中一步。

目的 请参阅
到下一步 创建 ActiveX DLL 的总结
从头开始 创建一个 ActiveX DLL