9

为什么当我使用遗嘱时,它Err.Raise 65536Err.Number值实际上是 5 而不是 65536?

根据Raise定义:Sub Raise(Number As Long, [Source], [Description], [HelpFile], [HelpContext]). 传递参数 isLongErr.Numberis also Long

那么为什么我不能使用大于 65535 的值呢?

Private Sub Command1_Click()
Dim a As Long
    On Error GoTo ErrCatch
    For a = 0 To 99999
        Err.Raise a
        DoEvents
    Next a
    Exit Sub
ErrCatch:
    ' this is where Err.Number is evaluated
    Resume Next
End Sub`
4

4 回答 4

11

MSDN 文档:

数字

必需的。标识错误性质的长整数。Visual Basic 错误在 0–65535 范围内;0-512 范围是为系统错误保留的;范围 513–65535 可用于用户定义的错误。在类模块中将 Number 属性设置为您自己的错误代码时,您将错误代码编号添加到 vbObjectError 常量。例如,要生成错误号 513,请将 vbObjectError + 513 分配给 Number 属性。

因此,即使您可以提交大于 65535 的值,任何大于 65535 的值都将变为错误 5。

于 2012-09-21T17:14:41.027 回答
10

除了“微软这么说”之外,还有更深的层次。您提出的错误编号是一个 32 位整数,因为这是 COM 规范的一部分,用于在组件之间传递错误。组件的所有公共方法实际上都是返回 HRESULT 作为返回值的函数;如果你有一个 VB 函数,它会秘密地将函数的返回值映射到一个 [out] 参数。HRESULT 值是一个由整堆值组成的位域;但为了简单起见,您可以将其分成两个 16 位部分。低 16 位包含实际的错误号,恰好在 0 到 65535 之间——无符号的 16 位范围。高 16 位有很多标准。最重要的是 0x0000____。所有使用这个的常量都以“S_”开头(代表成功)。最常用的 32 位值是 S_OK (0x00000000)。如果返回此值,则该函数已成功。大多数 VB 方法调用都会返回这个值。但是,任何设置了最高位的值都表明存在错误。在十六进制中,这些值看起来像 0x8___ 。有许多类别的错误。VB 默认返回的是 0x800A。然而,COM 规范只给你一个你可以正式使用的类,0x8004——它在 VB 中表示为常量 vbObjectError。

事实上,VB 建议您在 ActiveX DLL 或 EXE 中的公共方法引发错误时使用 vbObjectError 常量。你做不做都没有区别。这只是意味着调用代码收到的错误非常大且为负数,因此您必须将错误号与 &H0000FFFF 相加才能取回您的 16 位整数。有趣的是,它还建议你不要使用 ActiveX 控件方法执行此操作,可能是因为与 ActiveX 控件方法关联的高 16 位是 0x800A000。更有趣的是,当您默认引发错误时,VB 本身会将所有错误编号与 0x800A0000 进行“与”运算。同样,它会检测错误号是否类似于 0x800A____ - 如果是这样,无论如何都会为您删除高 16 位,因此您只需处理错误号本身。在我的工作场所,我们有许多 VB 组件。我们的标准是不使用 vbObjectError 或错误代码。这为我们省去了随后必须在调用代码中屏蔽它的麻烦。

例如,如果您有 COMPONENT1.CLASS1 和 COMPONENT2.CLASS2。CLASS1.Method1 调用 CLASS2.Method1。如果我在 CLASS2 中引发错误,那么我必须在 CLASS1.Method1 中处理它。按照微软的规定,我会这样写:

COMPONENT1.CLASS1

Function Method1()
    On Error GoTo ErrorHandler
    ...
ErrorHandler:
    If (Err.Number And vbObjectError) = vbObjectError Then
        Select Case Err.Number And (Not vbObjectError)
        Case Component2.EErrComponent2.ecBlahBlahError
            ... handle ...
        End Select
    End If
End Function

COMPONENT2.CLASS2

Enum EErrComponent2
    ecBlahBlahError = 513 ' Minimum error code
End Enum

Function Method1()
...
    Err.Raise EErrComponent1 Or vbObjectError
...
End Function

对多个组件重复此操作,此样板文件会有点令人厌烦,而且似乎实际上并没有给我们任何回报。

我们可能会这样做:

COMPONENT1.CLASS1

Function Method1()
    On Error GoTo ErrorHandler
    ...
ErrorHandler:
    Select Case Err.Number
    Case Component2.EErrComponent2.ecBlahBlahError
        ... handle ...
    End Select
End Function

COMPONENT2.CLASS2 枚举 EErrComponent2 ecBlahBlahError 结束枚举

Function Method1()
...
    Err.Raise EErrComponent1
...
End Function

我想知道是否有人在不使用 vbObjectError 时遇到过问题。我们当然没有。

于 2012-09-22T15:39:01.593 回答
9

错误 5 是

Run-Time Error '5': Invalid Procedure Call or Argument”

随着贾斯汀的回答,这将是有道理的。当您使用大于 65535 的整数调用 Raise 函数时,它会引发错误 5,因为它是无效参数。

你能显示一些代码,我可以帮你更好一点吗?

于 2012-09-21T17:13:56.300 回答
0

虽然Number被指定为 a Long,但在文档中Err.Raise说只有值 0-65535 是有效的。因此,您看到的错误实际上是因为您违反了Err.Raise.

为什么他们没有把它变成Integer一个谜(也许在未来扩大有效范围的情况下)。

于 2012-09-21T17:15:24.747 回答