作者:我hi7娘 | 来源:互联网 | 2023-08-07 18:01
HeresoneIdontunderstand.有一个我不明白。Giventhisclassmodule(strippeddowntothebareminimum
Here's one I don't understand.
有一个我不明白。
Given this class module (stripped down to the bare minimum necessary to reproduce the crash):
给定这个类模块(简化为再现崩溃所需的最小值):
VERSION 1.0 CLASS
BEGIN
MultiUse = -1 'True
END
Attribute VB_Name = "TestCrashClass"
Attribute VB_GlobalNameSpace = False
Attribute VB_Creatable = False
Attribute VB_PredeclaredId = True
Attribute VB_Exposed = False
Option Explicit
Public Function Init() As TestCrashClass
Attribute Init.VB_UserMemId = 0
Dim tcc As New TestCrashClass
Set Init = tcc
End Function
Public Property Get Data() As String
Data = "test data"
End Property
Can anyone tell me why Excel totally craps out when I type in this code:
有谁能告诉我为什么我输入这段代码时Excel会完全崩溃?
Sub MakeExcelCrash()
With TestCrashClass(
At this point, I this lovely message:
此时此刻,我要传达一个可爱的信息:
Even if I type in a full procedure without the offending parentheses and then try to add them later, I get the same crash.
即使我输入了一个完整的过程而没有出现问题的括号,然后再尝试添加它们,我也会得到相同的崩溃。
The only way I can get Excel not to crash is to copy/paste a set of ()
from somewhere else to this line of code.
使Excel不崩溃的唯一方法是将一组()从其他地方复制/粘贴到这一行代码。
Sub MakeExcelCrash()
With TestCrashClass()
Debug.Print .Data
End With
End Sub
If the Init()
method has a parameter—even an optional one—it won't crash when the opening paren is typed.
如果Init()方法有一个参数—甚至是可选的-它在打开paren的时候不会崩溃。
I'm more curious about why this happens than ways around it; it doesn't actually come up that often in my code and when it does I can fix it with a change in approach, but I'm really frustrated that I don't know what's causing these crashes. So maybe someone who knows more about the inner working of VBA can explain it to me?
我更好奇的是为什么会发生这种情况,而不是围绕它;它在我的代码中并不经常出现,当它出现时,我可以通过改变方法来修复它,但是我真的很沮丧,因为我不知道是什么原因导致了这些崩溃。所以,也许有人对VBA的内部工作有更多的了解,可以给我解释一下吗?
3 个解决方案
10
You don't even need the With
block. Any attempt to type (
after the class name takes Excel down.
你甚至不需要带块。任何输入尝试(在类名取出Excel后)。
The problem is that you have the VB_PredeclaredId
set to true and the default member is trying to return itself. When you attach a debugger to the dying Excel instance, you can see that the underlying issue is a stack overflow:
问题是,您将VB_PredeclaredId设置为true,并且默认成员正在尝试返回自己。当您将调试器附加到垂死的Excel实例时,您可以看到底层问题是堆栈溢出:
Unhandled exception at 0x0F06EC84 (VBE7.DLL) in EXCEL.EXE: 0xC00000FD: Stack overflow (parameters: 0x00000001, 0x00212FFC).
EXCEL中0x0F06EC84 (VBE7.DLL)处未处理的异常。EXE: 0xC00000FD:栈溢出(参数:0x00000001, 0x00212FFC)。
When you type With TestCrashClass(
, what happens is that VBA starts looking for an indexer on the default property, because Init()
doesn't have any properties. For example, consider a Collection
. You can use the default property's (Item
) indexer like this:
当您键入TestCrashClass时(发生的情况是VBA开始寻找默认属性的索引器,因为Init()没有任何属性。例如,考虑一个集合。您可以使用默认属性的(项目)索引器,如下所示:
Dim x As Collection
Set x = New Collection
x.Add 42
Debug.Print x(1) '<--indexed access via default member.
This is exactly equivalent to Debug.Print x.Items(1)
. This is where you start running into problems. Init()
doesn't have parameters, so VBA starts drilling down through the default members to find the first one that has an indexer so IntelliSense can display the parameter list. It starts doing this:
这完全等同于调试。打印x.Items(1)。这就是你开始遇到问题的地方。Init()没有参数,因此VBA开始通过默认成员查找第一个具有索引器的成员,以便IntelliSense可以显示参数列表。它开始这样做:
x.[default].[default].[default].[default].[default]...
x。(默认)。(默认)。(默认)。(默认)。(默认)……
In your case, it's creating an infinite loop because [default]
returns x
. The same thing happens in the Collection
code above (except it finds one):
在您的例子中,它正在创建一个无限循环,因为[default]返回x。
Throw in the fact that you have a default instance, and the end result is something like this:
假设你有一个默认实例,最终结果是这样的:
Private Sub Class_Initialize()
Class_Initialize
End Sub