几个月前我在 VBA 中发现了一个错误,但找不到合适的解决方法。这个错误真的很烦人,因为它限制了一个很好的语言功能。
使用自定义集合类时,通常希望有一个枚举器,以便可以在For Each循环中使用该类。这可以通过添加以下行来完成:
Attribute [MethodName].VB_UserMemId = -4 'The reserved DISPID_NEWENUM
Run Code Online (Sandbox Code Playgroud)
紧接在函数/属性签名行之后:
'@Enumerator然后同步不幸的是,在 x64 上,使用上述功能会导致写入错误的内存并在某些情况下导致应用程序崩溃(稍后讨论)。
重现错误
CustomCollection 班级:
VERSION 1.0 CLASS
BEGIN
MultiUse = -1 'True
END
Attribute VB_Name = "CustomCollection"
Attribute VB_GlobalNameSpace = False
Attribute VB_Creatable = False
Attribute VB_PredeclaredId = False
Attribute VB_Exposed = False
Option Explicit
Private m_coll As Collection
Private Sub Class_Initialize()
Set m_coll = New Collection
End Sub
Private Sub Class_Terminate()
Set m_coll = Nothing
End …Run Code Online (Sandbox Code Playgroud) 对于较大的 VBA 项目(40,000 多行代码),我无法正确使用接口,因为应用程序(我主要使用 Excel)会经常崩溃。显然,这是因为代码不能保持编译状态(根据我的理解,VBA 代码被编译为 P 代码,稍后解释)。当 VBA 项目受密码保护时,我主要会得到这种行为。
该文章描述了同样的情况。转至第 2.3 节
例如:
IClass接口:
Option Explicit
Public Property Get SomeProperty() As Double
End Property
Run Code Online (Sandbox Code Playgroud)
Class1:
Option Explicit
Implements IClass
Private Property Get IClass_SomeProperty() As Double
IClass_SomeProperty = 0
End Property
Run Code Online (Sandbox Code Playgroud)
标准模块中的代码:
Option Explicit
Sub TestInterface()
Dim obj As IClass
Set obj = New Class1
Debug.Print obj.SomeProperty 'Crashes here on large projects only
End Sub
Run Code Online (Sandbox Code Playgroud)
正如预期的那样,Debug.Print obj.SomeProperty如果项目很小,该行可以正常工作并在“立即”窗口中打印 0。但是,在大型项目中,调用此行时应用程序会崩溃。在IClass_SomeProperty没有达到(记录到文件阐明了这一点)。
正如上面提到的文章,有一些方法可以暂时避免这个问题:
我遇到了一个令人讨厌的 VBA 错误,它使Property Get过程调用变得非常慢。这很可能是由于最近的 Office 更新(我有 Office365)造成的。它仅影响 32 位 CPU 上的 Excel。
错误
考虑一个Class1仅使用代码调用的类:
Option Explicit
Public Property Get Something() As Long: End Property
Run Code Online (Sandbox Code Playgroud)
基本上,一个Get返回零的属性。
运行以下代码时(在标准 .bas 模块中):
Public Sub TestSpeed()
Const iterations As Long = 10000
Dim i As Long
Dim t As Double
Dim coll As New Collection
'
t = Timer
For i = 1 To iterations
coll.Add New Class1
CallGet coll.Item(coll.Count)
Next i
Debug.Print iterations & " loops took " …Run Code Online (Sandbox Code Playgroud)