【问题标题】:How to refactor VB6 code to prevent run-time errors如何重构 VB6 代码以防止运行时错误
【发布时间】:2010-05-09 06:27:42
【问题描述】:

VB6 应用程序在多个地方遇到运行时错误。

我知道这是错误处理不当造成的,但是否可以分析代码以查看哪些地方容易受到运行时错误的影响?

【问题讨论】:

    标签: error-handling vb6 runtime-error


    【解决方案1】:

    任何应用程序都容易受到运行时错误的影响,因为对外部资源的调用没有错误处理,因此您可以将这些点确定为开始。

    我使用了一个免费工具(很多年前),它可以将错误处理改进为 VB6 代码,它至少会记录错误及其发生的时间点。

    这里是:The HuntErr Addin for easy error handling in VB6

    【讨论】:

      【解决方案2】:

      您需要确保代码库中的每个方法(函数、子函数、属性...)都有错误处理语句。可能不是每一个都可以生成运行时错误,但这将保护应用程序在没有大量前期分析的情况下不会崩溃。

      确保在任何可执行代码行之前有一个带有标签的语句“On Error GoTo...”,然后确保将该标签和一些错误处理代码放在方法的底部。我使用了一个名为MZ-Tools 3.0 的免费工具,它允许您自动包含此文本。选项中有一个错误处理程序选项卡,可用于指定要放入的文本和位置。这是我的样子:

          On Error GoTo l{PROCEDURE_NAME}_Error
      
          {PROCEDURE_BODY}
      
          Exit {PROCEDURE_TYPE}
      
      l{PROCEDURE_NAME}_Error:
      
          LogError "{MODULE_NAME}", "{PROCEDURE_NAME}", Err, Err.Description
      

      然后我只需确保 LogError 函数存在并将错误写入一个我可以查看的日志文件。

      【讨论】:

      • 我遇到的问题是代码已经充满了各种错误处理技术,我不想破坏代码中有意忽略错误的任何部分。您的建议是否会使代码功能与以前完全相同,但会记录错误?
      • 这将记录它遇到的每个错误。如果有部分使用 On Error Resume Next (或者可能是其他 On Error 语句)故意忽略错误,添加这将改变行为。如果方法中已经有 On Error 语句,则不需要添加。
      • 如果一个模块在模块中的某个地方有 On Error Resume Next 或 On Error Goto 0 那么上面的代码有什么帮助?
      【解决方案3】:

      VB6 应用程序中常见的运行时错误来源包括

      • 访问集合中不存在的键
      • 在没有任何东西的对象上调用方法或属性
      • 当字符串为空时使用CLng将字符串转换为数字
      • 访问超出其长度的数组(例如在调用 Split 并假设字符串具有您期望的片段数之后)

      因此,除了按照其他人的建议进行操作并分析实际错误的来源之外,您还可以从在代码中查找诸如此类的区域开始,并在它们周围进行适当的错误处理。请记住,通常最好的“错误处理”根本不涉及使用 On Error,而是通过检查这些边界情况来提前防止错误,例如

      • 如果不是对象就什么都不是
      • 如果 Len(string) > 0
      • 如果 UBound(array) > x

      等等……

      【讨论】:

        【解决方案4】:

        On Error GoTo 的建议和bwarner 提到的常见错误在这里都有一些很好的答案。

        但可能会扩大范围并利用内置工具来分析断点、监视表达式等代码,尤其适用于调试运行时错误、本地窗口(在调试中经常被忽略,但非常强大)和调用堆栈.你可以从这里获得很多很棒的信息:Debugging Your Code and Handling Errors

        考虑其他可能会有所帮助的事情:

        1. 投资一个可以帮助你的工具 使用CodeSMART 2009 for VB6VB Project Analyzer 之类的分析。
        2. 尝试移植现有应用程序 到 VB.NET - 不实际移植和 使用,但要查看转换日志 需要解决的问题。

        【讨论】:

          【解决方案5】:

          按照 Ryan 的回答和回应的评论,您没有必须每个 例程中进行错误处理,只需在每个 Event 和 Sub Main()(以及 API 回调如果他们还没有)。

          API 回调指的是由 Win32API 直接调用的例程,通常使用 AddressOf 传递给 Declared 函数。 (即在您的代码中搜索 AddressOf 并确保所有作为参数提及的例程都有错误处理程序来捕获错误并且不允许它们尝试冒泡。)

          我刚刚注意到这并没有真正回答最初提出的问题(尽管给出了回应 Ryan 回答的评论 是一个很好的第一步):一旦你在每个事件等,您都会捕获所有错误,但您将无法直接分析所有错误发生的位置。您需要将错误记录至少扩展到记录错误的事件调用的所有例程,以便更准确地定位每个错误的确切来源。

          【讨论】:

          • “API 回调”是什么意思?
          【解决方案6】:

          在 VB6 中,运行时错误发生在事件函数在没有错误处理的情况下被调用时。所以至少你所有的事件处理函数(比如 Form.Open())应该被一个错误处理程序包围(是的,我知道 VB6 没有它们),它可以很好地像这样实现(我们在所有应用程序中都这样做)像这样):

          将此作为每个事件处理函数的第一行(它是一个大的有效标签,在末尾设置 On Error):

          ¦¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯: On Error GoTo ErrorHandler:
          

          现在在所有这些函数的末尾使用它:

          ¦____________________________________________________________________________________________________________________________________: Exit Sub
          ErrorHandler: handleError CodeDb, "Form_frm_filter_deletecolum", "cmd_deletecolum_Click", err.Number, err.description, err.Source, err.LastDllError, err.Helpfile, err.HelpContext, Erl: err.Clear
          

          但是用模块名和函数名替换这两个字符串。并将每个 On Error Goto 0 替换为 On Error Goto ErrorHandler

          现在使用给定的参数创建一个函数 handleError(在我的应用程序中,它会自动将错误报告发送到我们的错误跟踪系统),并显示一个很好的错误消息。

          我们甚至进一步推动了这一点,通过一个预构建的过程,将类似的行添加到所有其他(意味着非事件函数,或仅由其他函数调用的函数),以记住发生错误的行并累积完整的堆栈跟踪(是的,VB6 中的堆栈跟踪!)。此外,此过程将行号添加到每一行,以便在错误处理程序的 Erl 部分中给出它们。

          我们的工具是作为一些 MS Access 模块编写的,所以我不能简单地为您提供它,但您知道您必须去哪里。

          【讨论】:

          • 您拥有这些大品牌的原因是什么?是为了向可能查看代码的人隐藏错误处理代码吗?
          • 没错!这主要包括我和我的开发人员伙伴,因为我们发现了所有其他侵入的可能性,而且这在 VB IDE 中看起来仍然不错。
          猜你喜欢
          • 2014-07-23
          • 2019-01-30
          • 2017-05-07
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多