【问题标题】:VB6 IDE crashes after application terminates应用程序终止后 VB6 IDE 崩溃
【发布时间】:2019-10-31 09:47:27
【问题描述】:

我团队中的几个开发人员都遇到了这个问题。我们可以在 IDE 中正常运行我们的应用,但是当我们最终退出应用时,IDE 本身就会崩溃

崩溃的形式是

“Visual Basic 已停止工作”

我们是否很好地退出我们的应用程序或在调试器中强制停止它并不重要;结果相同(IDE 崩溃)。


应用的退出顺序是:

  1. 用户从菜单中选择“退出”

  2. 菜单事件处理程序调用Unload Me

  3. Form_QueryUnload 事件处理程序触发

  4. Form_Unload 事件处理程序触发。它确实:

 

'close all sub forms
For i = Forms.Count - 1 To 1 Step -1
    Unload Forms(i)
Next

然后保存一些数据然后做Exit Sub


我们倾向于运行一个包含 5-6 个项目的组文件。

此错误有时似乎会消失,但有时会出现,似乎是随机的。我不知道是什么因素影响了这一点。

如果我们实际上不运行应用程序,只运行 IDE,那么它可以正常工作,我们可以正常退出 IDE。

有人见过这个吗?有任何想法吗?谢谢!

【问题讨论】:

  • 我也看到了这种情况。不是很常见,而且看起来像你一样随机。我也没有想出解决办法。
  • 您是否在项目中对 Windows 消息使用 any API 挂钩?如果是这样,请确保它们仅在编译后的应用程序中使用,不是在 IDE 中。
  • 你能分享你的退出代码吗?
  • FWIW,我还发现你有一个 VB6 开发人员“团队”很有意思。真的很高兴听到。

标签: vb6 ide


【解决方案1】:

这肯定是由涉及子类化/挂钩的 VB6 对象泄漏引起的,而不仅仅是这些。

我们为摆脱这些崩溃所做的就是在各自的 Class/Form/UserControl 中使用 DebugInstanceInitDebugInstanceTerm 调用来检测我们所有的类(包括表单、用户控件、设计器和任何可以实例化的东西) InitializeTerminate 事件。

Public Sub DebugInstanceInit(sModuleName As String, sDebugID As String, oObj As Object)

Public Sub DebugInstanceTerm(sModuleName As String, sDebugID As String)

这些基本上随时跟踪应用程序正在使用的实例数量和类型。每个实例在DebugInstanceInit 中分配一个唯一的sDebugID,用作DebugIDs 集合中的键。此集合在Sub Main 中实例化为空,并且当应用程序终止时(即在主窗体的Form_Unload 中),此集合必须为空或留下固定数量的实例(例如正好 4 个),否则它的内容就是对象的种类我们正在泄漏。

什么解决了 IDE 崩溃问题?

请注意,集合被实例化到Sub Main,这意味着它必须在设计时保持Nothing。我们只需像这样在DebugInstanceInit 中进行简单检查

    If DebugIDs Is Nothing Then
        If Left$(sModuleName, 3) <> "ctx" Then
            DebugPrint "DebugInstanceInit", "mdErrorHandling", sDebugID & " " & LIB_NAME & "." & sModuleName & "." & FUNC_NAME_INITIALIZE & " (This should not happen)"
        End If
    Else
       ...
    End If

这基本上阻止了除了放置在表单上的原始用户控件之外的任何东西在设计时被实例化。这包括GlobalMultiUse 对象,这包括UC 属性正在访问的任何内容,因为UC 属性是一种在设计时肯定会访问的例程。

所以我们不得不在 UC 的大部分代码中大量使用 Ambient.UserMode 这样的检查

    If Ambient.UserMode Then
        Set .Picture = LoadStdPicture(ucsPicHelp)
    End If

事实证明,我们的 LoadStdPicture 全局函数正在实例化一些 cDibSections。好消息是,一旦您在 (This should not happen) 调试打印语句处设置断点,调用堆栈就会准确地向您显示违规 UC 的违规属性。

【讨论】:

  • 我认为这个答案是在正确的轨道上——我的特定程序中的问题原来源于第三方 OCX 库;当我将它更新到更新的版本时,问题得到了解决。谢谢你让我走上正轨。
  • 另外 - 我注意到你在这个主题上发表的一些其他类似的帖子,但我不确定它们是否包含你非常有用的 DebugInstance...() 过程的完整来源。也许如果您在此处添加它们(或完整来源的链接),那将是一个好处!
  • @DaveInCaz 这些可以像生成下一个顺序调试 id 并将实例信息添加到以 "#" &amp; sDebugID 作为键(两个 LoC)的集合一样简单,然后在终止时删除 "#" &amp; sDebugID 键(单个行)。一个更好的示例将是一个带有检测类和表单的整个项目,以及一个在应用程序拆卸时报告泄漏的 msgbox。 . .
【解决方案2】:

我相信another answer 对问题原因的技术评估是正确的。但简要描述一下我用来缩小源代码行的过程也可能很有用。就我而言,这个问题似乎是完全随机的,所以很难知道从哪里开始。

我的方法不是火箭科学 - 更多的是蛮力。本质上,我使用二进制搜索来排除/排除代码部分。第一步是注释掉整个启动过程,以便应用程序以空壳启动;这表明问题消失了(结果为空)。

之后我递归地注释了大约一半的代码,每次都测试问题。每个块都被评估为一个布尔值——它要么确实导致了问题,要么没有导致问题。然后在不排除的块中再次进行。

最终(并且比我预期的更快)这导致了一行代码访问了第三方控件的属性。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-11-10
    • 2011-05-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多