VBA 用户窗体为其参数之一给出 运行-时间错误 91
VBA UserForm gives run-time error 91 for one of its parameters
我正在尝试通过 Sub 在 excel-VBA 中使用参数创建同一个无模式用户窗体的多个实例。
我可以使用我要分配的三个参数中的两个使其工作,但第三个参数一直返回我
"Run-time Error '91': Object variable or With block variable not set"
我不明白为什么。
可能是我没有看到的明显错别字,但我确实无法指出问题所在。
这是我的代码:
Sub AskToClose(targetWksht As Worksheet, targetRow As Integer, test As String)
Dim newInstanceOfMe As Object
Set newInstanceOfMe = UserForms.Add("MOVE_TO_CLOSED") 'MOVE_TO_CLOSED is the name of my UserForm
newInstanceOfMe.targetWksht = targetWksht 'If I comment this line it works just fine, otherwise Run-time error 91
newInstanceOfMe.targetRow = targetRow
newInstanceOfMe.test = test
newInstanceOfMe.Show vbModeless
End Sub
_____________________________________________________________________
Sub test()
Dim openWksht As Worksheet
Set openWksht = Worksheets("OPEN WO") 'The worksheet exists and works just fine everywhere else
Call AskToClose(openWksht, 2, "test 2")
Call AskToClose(openWksht, 3, "test 3")
Call AskToClose(openWksht, 4, "test 4")
Set openWksht = Nothing 'I tried to comment this line just in case, same result...
End Sub
_____________________________________________________________________
'My MOVE_TO_CLOSED UserForm parameters
Public targetWksht As Worksheet
Public targetRow As Integer
Public test As String
newInstanceOfMe.targetWksht = targetWksht
此语句为 Rubberduck(我管理的开源 VBIDE 加载项项目)中的 Value Required 检查生成错误级别 代码质量 检查结果。检查说明情况如下:
Object used where a value is required
The VBA compiler does not raise an error if an object is used in a place that requires a value type and the object's declared type does not have a suitable default member. Under almost all circumstances, this leads to a run-time error 91 'Object or With block variable not set' or 438 'Object doesn't support this property or method' depending on whether the object has the value 'Nothing' or not, which is harder to detect and indicates a bug.
VBA中有两种赋值方式:值赋值(Let
)和引用赋值 (Set
)。 Let
关键字为redundant/optional/obsolete赋值:
Dim foo As Long
foo = 2 + 2
Let foo = 2 + 2 '<~ exactly equivalent to the above
因此,除非存在 Set
关键字,否则 VBA 会尝试进行赋值。如果对象有一个 default 成员,那可能会起作用——VBA 规范定义了 let-coercion 机制如何实现这一点。这就是如何将 Range
分配给一个值:
Sheet1.Range("A1") = 42
这是 隐式 分配给 Range.Value
,通过对 Range.[_Default]
的隐式成员调用,[=19= 的隐藏 属性 ] class.
如果赋值的右边也是一个对象,那么运算符的两边都会发生 let-coercion:
Sheet1.Range("A1") = Sheet1.Range("B1") '<~ implicit default member calls galore!
Sheet1.Range("A1").Value = Sheet1.Range("B1").Value
但是我们这里不是看Range
,我们看的是UserForm
,而UserForm
没有默认成员,所以let-coercion不可能发生......但编译器不会验证这一点,所以代码无论如何都会到达 运行 ......并在 运行 时间爆炸。
因此,对于未定义默认成员的 class 类型,我们正在查看双方都持有对象引用的 Let
赋值。
Something.SomeObject = someOtherObject
但是 VBA 不在乎没有默认成员 - 因为没有 Set
关键字,它会尽力按照您告诉它的方式去做,并强制这些成员将对象转化为值...显然失败了。
如果 Something.SomeObject
(左侧)是 Nothing
,那么 let-coercion 尝试将尝试调用不存在的默认成员——但是由于对象引用是 Nothing
, 该调用无效,并引发错误 91。
如果 Something.SomeObject
已经持有一个有效的对象引用,那么 let-coercion 尝试将更进一步,并失败并返回错误 438,因为没有要调用的默认成员。
如果 Something.SomeObject
有 个默认成员(并且引用不是 Nothing
),则值分配成功,不会引发错误。 .. 但没有分配对象引用,这可能是一个微妙的错误!
添加 Set
关键字使分配成为 参考分配 ,现在一切正常。
我正在尝试通过 Sub 在 excel-VBA 中使用参数创建同一个无模式用户窗体的多个实例。
我可以使用我要分配的三个参数中的两个使其工作,但第三个参数一直返回我
"Run-time Error '91': Object variable or With block variable not set"
我不明白为什么。 可能是我没有看到的明显错别字,但我确实无法指出问题所在。 这是我的代码:
Sub AskToClose(targetWksht As Worksheet, targetRow As Integer, test As String)
Dim newInstanceOfMe As Object
Set newInstanceOfMe = UserForms.Add("MOVE_TO_CLOSED") 'MOVE_TO_CLOSED is the name of my UserForm
newInstanceOfMe.targetWksht = targetWksht 'If I comment this line it works just fine, otherwise Run-time error 91
newInstanceOfMe.targetRow = targetRow
newInstanceOfMe.test = test
newInstanceOfMe.Show vbModeless
End Sub
_____________________________________________________________________
Sub test()
Dim openWksht As Worksheet
Set openWksht = Worksheets("OPEN WO") 'The worksheet exists and works just fine everywhere else
Call AskToClose(openWksht, 2, "test 2")
Call AskToClose(openWksht, 3, "test 3")
Call AskToClose(openWksht, 4, "test 4")
Set openWksht = Nothing 'I tried to comment this line just in case, same result...
End Sub
_____________________________________________________________________
'My MOVE_TO_CLOSED UserForm parameters
Public targetWksht As Worksheet
Public targetRow As Integer
Public test As String
newInstanceOfMe.targetWksht = targetWksht
此语句为 Rubberduck(我管理的开源 VBIDE 加载项项目)中的 Value Required 检查生成错误级别 代码质量 检查结果。检查说明情况如下:
Object used where a value is required
The VBA compiler does not raise an error if an object is used in a place that requires a value type and the object's declared type does not have a suitable default member. Under almost all circumstances, this leads to a run-time error 91 'Object or With block variable not set' or 438 'Object doesn't support this property or method' depending on whether the object has the value 'Nothing' or not, which is harder to detect and indicates a bug.
VBA中有两种赋值方式:值赋值(Let
)和引用赋值 (Set
)。 Let
关键字为redundant/optional/obsolete赋值:
Dim foo As Long
foo = 2 + 2
Let foo = 2 + 2 '<~ exactly equivalent to the above
因此,除非存在 Set
关键字,否则 VBA 会尝试进行赋值。如果对象有一个 default 成员,那可能会起作用——VBA 规范定义了 let-coercion 机制如何实现这一点。这就是如何将 Range
分配给一个值:
Sheet1.Range("A1") = 42
这是 隐式 分配给 Range.Value
,通过对 Range.[_Default]
的隐式成员调用,[=19= 的隐藏 属性 ] class.
如果赋值的右边也是一个对象,那么运算符的两边都会发生 let-coercion:
Sheet1.Range("A1") = Sheet1.Range("B1") '<~ implicit default member calls galore!
Sheet1.Range("A1").Value = Sheet1.Range("B1").Value
但是我们这里不是看Range
,我们看的是UserForm
,而UserForm
没有默认成员,所以let-coercion不可能发生......但编译器不会验证这一点,所以代码无论如何都会到达 运行 ......并在 运行 时间爆炸。
因此,对于未定义默认成员的 class 类型,我们正在查看双方都持有对象引用的 Let
赋值。
Something.SomeObject = someOtherObject
但是 VBA 不在乎没有默认成员 - 因为没有 Set
关键字,它会尽力按照您告诉它的方式去做,并强制这些成员将对象转化为值...显然失败了。
如果 Something.SomeObject
(左侧)是 Nothing
,那么 let-coercion 尝试将尝试调用不存在的默认成员——但是由于对象引用是 Nothing
, 该调用无效,并引发错误 91。
如果 Something.SomeObject
已经持有一个有效的对象引用,那么 let-coercion 尝试将更进一步,并失败并返回错误 438,因为没有要调用的默认成员。
如果 Something.SomeObject
有 个默认成员(并且引用不是 Nothing
),则值分配成功,不会引发错误。 .. 但没有分配对象引用,这可能是一个微妙的错误!
添加 Set
关键字使分配成为 参考分配 ,现在一切正常。