宏运行到一半报错,ScreenUpdating 还关着、打开的工作簿没关、事件被禁用,下一次运行就各种异常。错误处理不只是弹一个提示框,更重要的是无论成功还是失败,都把 Excel 的状态恢复原样。
On Error GoTo Handler ' 出错时跳到 Handler
On Error Resume Next ' 忽略错误,继续下一句
On Error GoTo 0 ' 关闭当前过程的错误处理
On Error Resume Next 只适合确实可以忽略错误的短小片段,例如关闭一个可能已经关闭的工作簿。不要用它包住整个宏,否则真正的错误会被静默吞掉。
出错后可以用 Err 读取信息:
Debug.Print Err.Number
Debug.Print Err.Description
Debug.Print Err.Source
Err.Clear
| 属性 | 含义 |
|---|---|
Err.Number |
错误号,0 表示没有错误 |
Err.Description |
错误描述,随 Office 语言变化 |
Err.Source |
产生错误的对象或项目 |
Err.Clear |
清除当前错误 |
判断错误类型要看 Err.Number,不要匹配 Description 文本;描述会随语言和版本变化。
常见错误号:
| 错误号 | 含义 |
|---|---|
| 9 | 下标越界(工作表名或数组索引不存在) |
| 13 | 类型不匹配 |
| 53 | 文件未找到 |
| 76 | 路径未找到 |
| 91 | 对象变量未设置(忘了 Set) |
| 1004 | 应用程序定义或对象定义错误(范围/工作表操作失败) |
Sub DoWork()
On Error GoTo CleanFail
Application.ScreenUpdating = False
Application.DisplayAlerts = False
' 业务代码
ThisWorkbook.Worksheets("数据").Range("A1").Value = 100
CleanExit:
Application.DisplayAlerts = True
Application.ScreenUpdating = True
Exit Sub
CleanFail:
MsgBox "错误 " & Err.Number & ":" & Err.Description, vbExclamation
Resume CleanExit
End Sub
关键点:
CleanExit 放在正常流程末尾,正常执行完直接 Exit Sub,不会掉进错误块;Resume CleanExit 跳到清理代码,而不是继续往下执行;Err.Raise。宏经常临时修改这些状态:
Application.ScreenUpdating = False
Application.DisplayAlerts = False
Application.EnableEvents = False
Application.Calculation = xlCalculationManual
对应恢复:
Application.ScreenUpdating = True
Application.DisplayAlerts = True
Application.EnableEvents = True
Application.Calculation = xlCalculationAutomatic
如果用户原本就是手动计算,直接恢复成自动会改变用户设置。更稳的做法是先保存原值:
Dim oldCalc As XlCalculation
oldCalc = Application.Calculation
Application.Calculation = xlCalculationManual
' ...
Application.Calculation = oldCalc
底层函数捕获错误、清理资源后,可以把错误继续抛给调用方:
Err.Raise Err.Number, Err.Source, Err.Description
不要用 Err.Raise 1004, ... 伪造一个通用错误号;保留原始错误号更利于排查。
Exit Sub,会继续执行 CleanFail 里的提示框;清理块前一定要 Exit Sub。Resume 死循环:Resume 会重试出错的那一句;如果错误条件没修复,会反复报错。修复后用 Resume Next 或 Resume 标签。On Error Resume Next 范围太大:后面的错误都被忽略,包括真正需要处理的问题;只包住确实可忽略的语句,之后立刻 On Error GoTo 0。Close,并单独处理。EnableEvents:事件被禁用后,工作簿的自动逻辑全部失效;清理块必须恢复。End 结束宏:End 会重置模块级变量和状态,可能留下未关闭的文件;用 Exit Sub。Err 被清除:Resume、Exit Sub 等会清除错误信息;需要记录时先把 Err.Number 存到变量。Err.Description = "文件未找到" 判断;用 Err.Number。合上页面,先回答,再展开对照。
On Error Resume Next 为什么不能包住整个宏?Exit Sub?Resume 和 Resume Next 有什么区别?Resume 重试出错的那一句;Resume Next 继续执行出错语句的下一句。
小程序版
微信扫码,随时查命令