Err对象

错误处理程序依靠 Err 对象的 Number 属性中的值来确定错误发生的原因。在其它任何错误发生之前,或在调用一个可能会导致错误发生的过程之前,错误处理程序应该先测试或存储 Err 对象中相关的属性值。Err 对象中的属性值只反映最近发生的错误。Err.Description 中包含有与 Err.Number 相关联的错误信息。

错误捕捉

VBA的语言特性类似于Visual Basic,应该说它们属于同一家族,所以,用来在Visual Basic中处理程序异常的方法也同样可以被用在VBA中。

在Visual Basic中,常用的程序错误处理的方式是设置或使用错误陷阱,以告诉应用程序当错误发生时转移到何处(或处理当错误发生时要运行的代码),通过在代码中定义标签来告知应用程序当错误发生时要转到的地方。这一点和C系列语言的错误处理方式是相同的。基本步骤如下:

  1. 设置一个有效的错误陷阱,以告诉应用程序发生错误时转移到何处继续运行。Visual Basic中的On Error语句可以使错误陷阱有效,并为应用程序指定错误处理的入口。
  2. 在错误程序的入口处编写响应错误的具体实现,如继续尝试执行之前的代码、或告知用户出错的具体原因以让用户尝试去解决等。
  3. 退出错误处理。

核心语句

  1. Sub Example():
  2. On Error GoTo Err_Handle
  3. .... some expression ....
  4. Exit Sub
  5. Err_Handle:
  6. .... Err handle expression ....
  7. Exit sub / Resume Next
  8. End Sub

不处理错误,由系统抛出 On Error Goto 0
不处理错误,继续执行 On Error Resume Next

GoTo line: 启用在所需的行参数中指定的行开始的错误处理例程。指定的行必须与On Error语句在相同的过程中,否则将发生编译时错误。
GoTo 0:禁用当前过程中启用的错误处理程序并将其重置为Nothing。
GoTo -1:禁用当前过程中启用的异常并将其重置为Nothing。
Resume Next:指定发生运行时错误时,控制权转到发生错误的语句之后的语句,并从该点继续执行。

Resume

Resume 从产生错误的语句恢复运行。 Resume 从产生错误的语句下一句运行 Resume Line 跳转到指定行

特别用法

On Error语句除了在VBA中被用来进行错误处理外,还有一些特殊的用途,下面是一个例子。

'Check whether the key in the collection of
Public Function KeyExists(col As Collection, Key) As Boolean
On Error Resume Next
Dim x As Variant
x = col.Item(Key)
KeyExists = Not (Err.Number = 5)
On Error GoTo 0
End Function

推荐结构

Ref:https://zhuanlan.zhihu.com/p/27224586

经典式

Sub Example():
  On Error GoTo Err_Handle
  .... some expression ....
  Exit Sub
  Err_Handle:
  .... Err handle expression ....
  Exit sub / Resume Next
End Sub

If Err.number跳过式

If Len(Dir(Path)) > 0 Then

On Error Resume Next
Set wb = Workbooks.Open(FileName:=Path, ReadOnly:=True, UpdateLinks:=False)
      If Err.Number > 0 Then '核心:如果上句运行失败,此处会有错误代码跳过运行
        q = "Open file again with Repair option"
        wb.Close savechanges:=False
        Set wb = Nothing
        Set wb = Workbooks.Open(FileName:=Path, ReadOnly:=True, CorruptLoad:=XlCorruptLoad.xlRepairFile, UpdateLinks:=False) 'try fixing it
        DoEvents
    End If
End If

Err.Number集中处理机制

'-----Err number-----
Private Const ErrNoPermissions = -2147217900
Private Const ErrCannotLocateURL = -2146697211
Private Const ErrDbDenyConnect = -2147217843
Private Const ErrCannotFoundDbProvider = 3706
'--------------------

' Errors handle:
' Return    Description
' 0         Resume
' 1         Resume Next
' 2         Error
Function ErrorsHandle() As Integer
   Dim intMsgType As Integer, intResponse As Integer, strMsg As String
   Dim myDoc As Worksheet
   Set myDoc = ActiveSheet

   Select Case Err.Number
          Case ErrCannotLocateURL           ' Error -2146697211
             strMsg = "Cannot connect to the website specified. Please make sure the URL is correct and the website is available."
             intMsgType = vbRetryCancel
          Case ErrNoPermissions             ' Error -2147217900
             myDoc.Protect 'Protect the sheet if current user doesn't have permissions to access the data
             strMsg = "User " & glUserName & " doesnt have permissions to access the data."
             intMsgType = vbExclamation
          Case ErrCannotFoundDbProvider     ' Error 3706
             strMsg = "Please ensure 'Microsoft SQL Server Native Client for SQL2005' installed at first." & _
                      "You can download at :http://download.microsoft.com/download/4/4/D/" & _
                      "44DBDE61-B385-4FC2-A67D-48053B8F9FAD/sqlncli.msi"
             intMsgType = vbExclamation
          Case ErrDbDenyConnect             ' Error -2147217843
             myDoc.Protect 'Protect the sheet if current user doesn't have permissions to connect the database
             strMsg = "Database login failed for user '" & glUserName & "'."
             intMsgType = vbExclamation
          Case Else
               strMsg = "Fatal error." & Err.Description & ".The error number is " & Err.Number
             intMsgType = vbCritical
   End Select

   intResponse = MsgBox(strMsg, intMsgType)
   Select Case intResponse
          Case 4, 6             ' Retry And Yes
             ErrorsHandle = 0
          Case 5                ' Ignore
             ErrorsHandle = 1
          Case Else             ' Cancel and Abort
             ErrorsHandle = 2
   End Select
End Function
Public Enum DebugMode
    Release = 0
    Debugger = 1
End Enum

Public Mode As DebugMode

Private Sub CommandButton1_Click()  
    Mode = DebugMode.Release 'Change the Mode value to Debugger or Release
    If Mode = Release Then
        On Error GoTo Error_Handle
    End If

  ' TODO Something

  Exit Sub

Error_Handle:
    errNum = ErrorsHandle
    If errNum = 0 Then
        Resume
    ElseIf errNum = 1 Then
        Resume Next
    Else
        Exit Sub
    End If
End Sub

触发错误

一般地程序执行过程中需有提示用户的时候更常见的用MSGBOX函数来完成人机对话,MSG好处是简易处理,缺点是当有语法或其他缺陷时,提示看起来不很专业,其实在VB中对错误提示有专门的对象,即ERR,我们如何自定义ERR错误呢,我们还是先来了解一下err对象 语法结构.
object.Raise number, source, description, helpfile, helpcontext
参数
object 必需的。总是Err 对象。
Number 必需的。Long型,识别错误性质。VB错误的范围在0–65535 之间。0–512 保留为系统错误;513–65535 可以用做用户定义的错误。当在模块中将Number 属性设置成用户的错误代码时,可将错误代码号添加到vbObjectError 常数上。例如,为了产生错误号513,可表达为 vbObjectError + 513 。
source 可选的。字符串表达式,为产生错误的对象或应用程序命名。当设置对象的这一属性时,要使用窗体 project.class。如果没有指定 source,则使用当前VB工程的程序设计ID。
description 可选的。描述错误的字符串表达式。如果没有指定,则检查 Number 的值。如果可以将错误映射成VB 运行时错误代码,则将 Error 函数返回的字符串作为 Description 使用。如果没有与 Number 对应的 VB错误,则要用到消息“应用程序定义的错误或对象定义的错误”。
helpfile 可选的。帮助文件的完整限定的路径,在帮助文件中可以找到有关错误的帮助信息。如果没有指定,则VB会使用 VB帮助文件的完整限定的驱动器、路径和文件名。
helpcontext 可选的。识别 helpfile 内的标题的上下文 ID,而 helpfile 提供有助于了解错误的描述。如果省略,则使用处理有关错误的 VB 帮助文件的上下文 ID,该 ID 与 Number 属性对应。
示例代码
Sub TEST()
Err.Raise vbObjectError + 513, “MyProj.MyObject “, “N>100 “, “c:\MyProj\MyHelp.Hlp “, MyContextID
End Sub

常见错误代码

代码 信息
3没有返回的GoSub
5无效的过程调用
6溢出
7内存不足
9数组索引超出范围
10此数组为固定的或暂时锁定
11除以零
13类型不符合
14字符串空间不足
16表达式太复杂
17不能完成所要求的操作
18发生用户中断
20没有恢复的错误
28堆栈空间不足
35没有定义 子程序、函数,或属性
47DLL 应用程序的客户端过多
48装入 DLL 时发生错误
49DLL 调用规格错误
51内部错误
52错误的文件名或数目
53文件找不到
54错误的文件方式
55文件已打开
57 I/O 设备错误
58文件已经存在
59记录的长度错误
61磁盘已满
62输入已超过文件结尾
63记录的个数错误
67文件过多
68设备不可用
70没有访问权限
71磁盘尚未就绪
74不能用其他磁盘机重命名
75路径/文件访问错误
76找不到路径
91尚未设置对象变量或 With 区块变量
92For循环没有被初始化
93无效的模式字符串
94Null 的使用无效
97不能在对象上调用 Friend 过程,该对象不是定义类的实例
298系统 DLL 不能被加载
320在指定的文件中不能使用字符设备名
321无效的文件格式
322不能建立必要的临时文件
325源文件中有无效的格式
327未找到命名的数据值
328非法参数,不能写入数组
335不能访问系统注册表
336ActiveX 部件不能正确注册
337未找到 ActiveX 部件
338ActiveX 部件不能正确运行
360对象已经加载
361不能加载或卸载该对象
363未找到指定的 ActiveX 控件
364对象未卸载
365在该上下文中不能卸载
368指定文件过时。该程序要求较新版本
371指定的对象不能用作供显示的所有者窗体
380属性值无效
381无效的属性数组索引
382属性设置不能在运行时完成
383属性设置不能用于只读属性
385需要属性数组索引
387属性设置不允许
393属性的取得不能在运行时完成
394属性的取得不能用于只写属性
400窗体已经显示,不能显示为模式窗体
402代码必须先关闭顶端模式窗体
419允许使用否定的对象
422找不到属性
423找不到属性或方法
424需要对象
425无效的对象使用
429ActiveX 部件不能建立对象或返回对此对象的引用
430类不支持自动操作
432在自动操作期间找不到文件或类名
438对象不支持此属性或方法
440自动操作错误
442连接至型态程序库或对象程序库的远程处理已经丢失
443自动操作对象没有默认值
445对象不支持此动作
446对象不支持指定参数
447对象不支持当前的位置设置
448找不到指定参数
449参数无选择性或无效的属性设置
450参数的个数错误或无效的属性设置
451对象不是集合对象
452序数无效
453找不到指定的 DLL 函数
454找不到源代码
455代码源锁定错误
457此键已经与集合对象中的某元素相关
458变量使用的型态是 Visual Basic 不支持的
459此部件不支持事件
460剪贴板格式无效
未找到方法或数据成员
462远程服务器机器不存在或不可用
463类未在本地机器上注册
480不能创建 AutoRedraw 图象
481图片无效
482打印机错误
483打印驱动不支持指定的属性
484从系统得到打印机信息时出错。 确保正确设置了打印机
485无效的图片类型
486不能用这种类型的打印机打印窗体图象
520不能清空剪贴板
521不能打开剪贴板
735不能将文件保存至 TEMP 目录
744找不到要搜寻的文本
746取代数据过长
1004 引用的对象错误或无对象
31001内存溢出
31004无对象
31018未设置类
31027不能激活对象
31032不能创建内嵌对象
31036存储到文件时出错
31037从文件读出时出错