x64 사용자 지정 클래스의 각 열거에 대한 버그
몇 달 전에 VBA에서 버그를 발견했는데 적절한 해결 방법을 찾을 수 없었습니다.그 버그는 좋은 언어 기능을 제한하기 때문에 정말 짜증난다.
Custom Collection Class에서 할 수 입니다.For Each
할수 있습니다.
Attribute [MethodName].VB_UserMemId = -4 'The reserved DISPID_NEWENUM
다음 중 하나에 의해 기능/기능 시그니처 행 바로 뒤에 표시됩니다.
- 클래스 모듈 내보내기, 텍스트 편집기에서 내용 편집, 다시 가져오기
- 러버덕 주석 사용
'@Enumerator
syncronizing syncronizing syncronizing syncronizing syncronizing syncronizing syncronizing.
유감스럽게도 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 Sub
Public Sub Add(v As Variant)
m_coll.Add v
End Sub
Public Function NewEnum() As IEnumVARIANT
Attribute NewEnum.VB_UserMemId = -4
Set NewEnum = m_coll.[_NewEnum]
End Function
표준 모듈의 코드:
Option Explicit
Sub Main()
#If Win64 Then
Dim c As New CustomCollection
c.Add 1
c.Add 2
ShowBug c
#Else
MsgBox "This bug does not occur on 32 bits!", vbInformation, "Cancelled"
#End If
End Sub
Sub ShowBug(c As CustomCollection)
Dim ptr0 As LongPtr
Dim ptr1 As LongPtr
Dim ptr2 As LongPtr
Dim ptr3 As LongPtr
Dim ptr4 As LongPtr
Dim ptr5 As LongPtr
Dim ptr6 As LongPtr
Dim ptr7 As LongPtr
Dim ptr8 As LongPtr
Dim ptr9 As LongPtr
'
Dim v As Variant
'
For Each v In c
Next v
Debug.Assert ptr0 = 0
End Sub
「」를 .Main
에서는 코드가 합니다.Assert
서다ShowBug
[ Locals ]창에서 로컬 변수가 갑자기 값이 변경된 것을 확인할 수 있습니다.
은 "ptr1"과.ObjPtr(c)
가 더 사용됩니다.NewEnum
method는 method의 ( 「」), 「ptrs」가 .ShowBug
메서드는 값(메모리 주소)으로 작성됩니다.
말할 필요도 없이 내부 로컬 ptr 변수를 삭제합니다.ShowBug
어플리케이션 크래시의 원인이 되는 것은 매우 확실합니다.
코드를 한 줄씩 밟아도 이 버그는 발생하지 않습니다!
버그 상세
버그와 .Collection
되어 있습니다.CustomCollection
New Enum enumenum능enumenumenumenumenumenumenumenum 。따라서 기본적으로 다음 중 하나를 실행해도 도움이 되지 않습니다(테스트 완료).
- , 「」의
Optional
- 함수 내에서 모든 코드 제거(아래 코드 참조)
IUnknown
IEnumVariant
Function
Property Get
-
Friend
★★★★★★★★★★★★★★★★★」Static
signature의 - DISPID_NEWENM을 Get의 Let 또는 Set에 추가하거나 Let/Set를 숨깁니다(즉, Let/Set를 비공개로 합니다).
2번입니다. ifCustomCollection
다음과 같이 됩니다.
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
Public Function NewEnum() As IEnumVARIANT
Attribute NewEnum.VB_UserMemId = -4
End Function
테스트에 사용되는 코드가 다음과 같이 변경됩니다.
Sub Main()
#If Win64 Then
Dim c As New CustomCollection
ShowBug c
#Else
MsgBox "This bug does not occur on 32 bits!", vbInformation, "Cancelled"
#End If
End Sub
Sub ShowBug(c As CustomCollection)
Dim ptr0 As LongPtr
Dim ptr1 As LongPtr
Dim ptr2 As LongPtr
Dim ptr3 As LongPtr
Dim ptr4 As LongPtr
Dim ptr5 As LongPtr
Dim ptr6 As LongPtr
Dim ptr7 As LongPtr
Dim ptr8 As LongPtr
Dim ptr9 As LongPtr
'
Dim v As Variant
'
On Error Resume Next
For Each v In c
Next v
On Error GoTo 0
Debug.Assert ptr0 = 0
End Sub
Main
그럼 같은 버그가 생성됩니다.
회피책
버그를 피하기 위한 신뢰성 높은 방법:
).
ShowBug
메서드) 및 컴백을 실시합니다.는 먼저 .For Each
행이 실행됩니다(즉, 같은 메서드의 임의의 위치에 있을 수 있음을 의미하기 전에 반드시 이전과 같은 행은 아닙니다).Sin 0 'Or VBA.Int 1 - you get the idea For Each v In c Next v
단점: 잊어버리기 쉽다
해요.
Set
오브젝트가 경우)에 수 있습니다.루프에서 사용되는 배리언트 상에 있을 수 있습니다(다른 오브젝트가 사용되지 않는 경우).와 같이 은 1번 포인트보다 .For Each
행이 실행됩니다.Set v = Nothing For Each v In c Next v
컬렉션을 'Collection'으로 해도 됩니다.
Set c = c
또는 c 매개 변수 전달ByVal
ShowBug
method(Set)의 IUnknown 에 합니다). Ref) : 참조 추가)
:' ' 를 사용하다'
EnumHelper
'CHANGE: 'CHANGE: 'CHANGE: 'CHANGE: 'CHANGE:VERSION 1.0 CLASS BEGIN MultiUse = -1 'True END Attribute VB_Name = "EnumHelper" Attribute VB_GlobalNameSpace = False Attribute VB_Creatable = False Attribute VB_PredeclaredId = False Attribute VB_Exposed = False Option Explicit Private m_enum As IEnumVARIANT Public Property Set EnumVariant(newEnum_ As IEnumVARIANT) Set m_enum = newEnum_ End Property Public Property Get EnumVariant() As IEnumVARIANT Attribute EnumVariant.VB_UserMemId = -4 Set EnumVariant = m_enum End Property
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 Sub Public Sub Add(v As Variant) m_coll.Add v End Sub Public Function NewEnum() As EnumHelper Dim eHelper As New EnumHelper ' Set eHelper.EnumVariant = m_coll.[_NewEnum] Set NewEnum = eHelper End Function
발신자 코드:
Option Explicit Sub Main() #If Win64 Then Dim c As New CustomCollection c.Add 1 c.Add 2 ShowBug c #Else MsgBox "This bug does not occur on 32 bits!", vbInformation, "Cancelled" #End If End Sub Sub ShowBug(c As CustomCollection) Dim ptr0 As LongPtr Dim ptr1 As LongPtr Dim ptr2 As LongPtr Dim ptr3 As LongPtr Dim ptr4 As LongPtr Dim ptr5 As LongPtr Dim ptr6 As LongPtr Dim ptr7 As LongPtr Dim ptr8 As LongPtr Dim ptr9 As LongPtr ' Dim v As Variant ' For Each v In c.NewEnum Debug.Print v Next v Debug.Assert ptr0 = 0 End Sub
는 "DISPID"에서
CustomCollection
를 누릅니다:: " " " "
For Each
.NewEnum
커스텀 컬렉션 대신 기능합니다.이것에 의해, 버그로 인한 크래시가 회피됩니다.함: 추가가 필요함
EnumHelper
. 를 추가하는 것을 잊기 쉽다..NewEnum
For Each
).line(실행시 오류만 트리거됨).
은 '어울릴 때(3)'가 때문입니다.c.NewEnum
을 당하다ShowBug
된 후 됩니다.Property Get EnumVariant
내 the의 EnumHelper
기본적으로 접근법 (1)은 버그를 피하는 방법입니다.
이 동작에 대한 설명은 무엇입니까?이 버그는 좀 더 우아한 방법으로 피할 수 있을까요?
편집
:CustomCollection
바이발「」를 생각해 .Class1
:
Option Explicit
Private m_collection As CustomCollection
Private Sub Class_Initialize()
Set m_collection = New CustomCollection
End Sub
Private Sub Class_Terminate()
Set m_collection = Nothing
End Sub
Public Sub AddElem(d As Double)
m_collection.Add d
End Sub
Public Function SumElements() As Double
Dim v As Variant
Dim s As Double
For Each v In m_collection
s = s + v
Next v
SumElements = s
End Function
이제 통화 루틴입니다.
Sub ForceBug()
Dim c As Class1
Set c = New Class1
c.AddElem 2
c.AddElem 5
c.AddElem 7
Debug.Print c.SumElements 'BOOM - Application crashes
End Sub
물론 이 예는 다소 강제적이지만 "하위" 개체의 사용자 지정 컬렉션을 포함하는 "상위" 개체가 있는 것은 매우 일반적이며 "상위" 개체는 "하위" 개체의 일부 또는 모두를 포함하는 작업을 수행할 수 있습니다.
, 이, 이, 이, 를 .Set
이 ""보다 앞에 .For Each
linedisplaces를 합니다.
무슨 일이 일어나고 있는가?
스택 프레임은 중복되어 있는 것처럼 보이지만 중복되어서는 안 됩니다.에 충분한 변수가 있는 경우ShowBug
메서드에서는 크래시를 방지하고 변수 값(발신측 서브루틴 내)은 단순히 변경됩니다.이는 변수에서 참조하는 메모리가 콜스택의 상부에 추가 또는 추가된 다른 스택프레임(착신측 서브루틴)에서도 사용되기 때문입니다.
몇 해 볼 수 있어요.Debug.Print
질문에서 동일한 코드에 대한 문장이 표시됩니다.
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 Sub
Public Sub Add(v As Variant)
m_coll.Add v
End Sub
Public Function NewEnum() As IEnumVARIANT
Attribute NewEnum.VB_UserMemId = -4
Debug.Print "The NewEnum return address " & VarPtr(NewEnum) & " should be outside of the"
Set NewEnum = m_coll.[_NewEnum]
End Function
또한 표준 .bas 모듈의 발신 코드는 다음과 같습니다.
Option Explicit
Sub Main()
#If Win64 Then
Dim c As New CustomCollection
c.Add 1
c.Add 2
ShowBug c
#Else
MsgBox "This bug does not occur on 32 bits!", vbInformation, "Cancelled"
#End If
End Sub
Sub ShowBug(ByRef c As CustomCollection)
Dim ptr0 As LongPtr
Dim ptr1 As LongPtr
Dim ptr2 As LongPtr
Dim ptr3 As LongPtr
Dim ptr4 As LongPtr
Dim ptr5 As LongPtr
Dim ptr6 As LongPtr
Dim ptr7 As LongPtr
Dim ptr8 As LongPtr
Dim ptr9 As LongPtr
'
Dim v As Variant
'
For Each v In c
Next v
Debug.Print VarPtr(ptr9) & " - " & VarPtr(ptr0) & " memory range"
Debug.Assert ptr0 = 0
End Sub
" " " 를합니다.Main
즉시 창에 다음과 같은 메시지가 나타납니다.
의 NewEnum
.ptr0
★★★★★★★★★★★★★★★★★」ptr9
의 변수ShowBug
이은 실제로는 스택프레임에서 값이기 수 있습니다.NewEnum
메서드의 등)IEnumVariant
않는 는, 되고 , 「」의 프레임 ) 합니다.ShowBug
「」의 으로서 「」NewEnum
메서드는 더 커집니다(예를 들어 로컬 변수를 추가하여 크기를 늘릴 수 있습니다).상위 스택프레임과 콜스택 내의 다음 프레임 간에 공유되는 메모리가 늘어납니다.
질문에 기재된 옵션을 사용하여 버그를 회피하면 어떻게 됩니까?「」를 만으로,Set v = Nothing
before For Each v In c
syslog, "syslog: "
값을 모두 하면, 「」(파란색 순서)이 「」라고 하는 을 알 수.NewEnum
은 return .ptr0
★★★★★★★★★★★★★★★★★」ptr9
의 변수ShowBug
회피책을되어 있는 것 .회피책을 사용하여 스택프레임이 올바르게 할당되어 있는 것 같습니다.
?For Each
NewEnum
모든 VBA 클래스는 IDispatch에서 파생됩니다(이러한 클래스는 IUnknown에서 파생됩니다).
의 경우For Each...
그 오브젝트의 "Loop"은 "Loop"으로 호출됩니다.IDispatch::Invoke
메서드는 a를 사용하여 호출됩니다.dispIDMember
4에 됩니다.에는 이미 를 VBA로 합니다.Collection에 이미 이러한 멤버가 있지만 VBA 커스텀클래스의 경우 자체 메서드를 다음과 같이 표시합니다.Attribute NewEnum.VB_UserMemId = -4
발동하다
Invoke
되고 있는 가 「」로 .For Each
은 어원이 .IDispatch
IUnknown::QueryInterface
아이디스패치 경우, 「 」Invoke
아이디스패치 이 이 이에요.For Each
에서 ""로 선언됨"As IUnknown
.ByRef
또는 글로벌 또는 클래스 멤버의 커스텀 컬렉션인지 확인합니다.질문에서 언급된 회피책 1번(즉, 다른 메서드를 호출)을 사용할 뿐이지만 확인할 수 없습니다.
후크 호출
가 아닌 VB를 할 수 .Invoke
스탠다드 .bas
모듈을 잠그려면 다음 코드가 필요합니다.
Option Explicit
#If Mac Then
#If VBA7 Then
Private Declare PtrSafe Function CopyMemory Lib "/usr/lib/libc.dylib" Alias "memmove" (Destination As Any, Source As Any, ByVal Length As LongPtr) As LongPtr
#Else
Private Declare Function CopyMemory Lib "/usr/lib/libc.dylib" Alias "memmove" (Destination As Any, Source As Any, ByVal Length As Long) As Long
#End If
#Else 'Windows
'https://msdn.microsoft.com/en-us/library/mt723419(v=vs.85).aspx
#If VBA7 Then
Public Declare PtrSafe Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (Destination As Any, Source As Any, ByVal Length As LongPtr)
#Else
Private Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (Destination As Any, Source As Any, ByVal Length As Long)
#End If
#End If
#If Win64 Then
Private Const PTR_SIZE As Long = 8
#Else
Private Const PTR_SIZE As Long = 4
#End If
#If VBA7 Then
Private newInvokePtr As LongPtr
Private oldInvokePtr As LongPtr
Private invokeVtblPtr As LongPtr
#Else
Private newInvokePtr As Long
Private oldInvokePtr As Long
Private invokeVtblPtr As Long
#End If
'https://learn.microsoft.com/en-us/windows/win32/api/oaidl/nf-oaidl-idispatch-invoke
Function IDispatch_Invoke(ByVal this As Object _
, ByVal dispIDMember As Long _
, ByVal riid As LongPtr _
, ByVal lcid As Long _
, ByVal wFlags As Integer _
, ByVal pDispParams As LongPtr _
, ByVal pVarResult As LongPtr _
, ByVal pExcepInfo As LongPtr _
, ByRef puArgErr As Long _
) As Long
Const DISP_E_MEMBERNOTFOUND = &H80020003
'
Debug.Print "The IDispatch::Invoke return address " & VarPtr(IDispatch_Invoke) & " should be outside of the"
IDispatch_Invoke = DISP_E_MEMBERNOTFOUND
End Function
Sub HookInvoke(obj As Object)
If obj Is Nothing Then Exit Sub
#If VBA7 Then
Dim vTablePtr As LongPtr
#Else
Dim vTablePtr As Long
#End If
'
newInvokePtr = VBA.Int(AddressOf IDispatch_Invoke)
CopyMemory vTablePtr, ByVal ObjPtr(obj), PTR_SIZE
'
invokeVtblPtr = vTablePtr + 6 * PTR_SIZE
CopyMemory oldInvokePtr, ByVal invokeVtblPtr, PTR_SIZE
CopyMemory ByVal invokeVtblPtr, newInvokePtr, PTR_SIZE
End Sub
Sub RestoreInvoke()
If invokeVtblPtr = 0 Then Exit Sub
'
CopyMemory ByVal invokeVtblPtr, oldInvokePtr, PTR_SIZE
invokeVtblPtr = 0
oldInvokePtr = 0
newInvokePtr = 0
End Sub
는 '우리'를 하고 있다.Main2
method 모듈합니다.
Option Explicit
Sub Main2()
#If Win64 Then
Dim c As Object
Set c = New CustomCollection
c.Add 1
c.Add 2
'
HookInvoke c
ShowBug2 c
RestoreInvoke
#Else
MsgBox "This bug does not occur on 32 bits!", vbInformation, "Cancelled"
#End If
End Sub
Sub ShowBug2(ByRef c As CustomCollection)
Dim ptr00 As LongPtr
Dim ptr01 As LongPtr
Dim ptr02 As LongPtr
Dim ptr03 As LongPtr
Dim ptr04 As LongPtr
Dim ptr05 As LongPtr
Dim ptr06 As LongPtr
Dim ptr07 As LongPtr
Dim ptr08 As LongPtr
Dim ptr09 As LongPtr
Dim ptr10 As LongPtr
Dim ptr11 As LongPtr
Dim ptr12 As LongPtr
Dim ptr13 As LongPtr
Dim ptr14 As LongPtr
Dim ptr15 As LongPtr
Dim ptr16 As LongPtr
Dim ptr17 As LongPtr
Dim ptr18 As LongPtr
Dim ptr19 As LongPtr
'
Dim v As Variant
'
On Error Resume Next
For Each v In c
Next v
Debug.Print VarPtr(ptr19) & " - " & VarPtr(ptr00) & " range on the call stack"
Debug.Assert ptr00 = 0
End Sub
「」의하려면 , 더미의 합니다.IDispatch_Invoke
더 커집니다(메모리 오버랩이 커집니다).
만, 는 결코 하지 않습니다.NewEnum
에 의한 Invoke
할당되었습니다.스택 프레임이 다시 잘못 할당되었습니다.
하다, 하다, 하다, 하다를 Set v = Nothing
before For Each v In c
결과는 다음과 같습니다.
스택 프레임이 올바르게 할당되어 있다(녹색으로 정렬되어 있다).은, 이 가, 이 문제가, 이 문제가, 이 문제가, 이 문제의 원인이 아니라는 것을 .NewEnum
방법에는 대체 이 없습니다. 대체 할 수 없습니다.Invoke
방법.우리보다 먼저 무슨 일이 일어나고 있다Invoke
출됩니니다다
마지막 예시입니다.) 「」를 해 주세요.Class1
를 실행하면Main3
다음 코드로 지정합니다.
Option Explicit
Sub Main3()
#If Win64 Then
Dim c As New Class1
ShowBug3 c
#Else
MsgBox "This bug does not occur on 32 bits!", vbInformation, "Cancelled"
#End If
End Sub
Sub ShowBug3(ByRef c As Class1)
Dim ptr0 As LongPtr
Dim ptr1 As LongPtr
Dim ptr2 As LongPtr
Dim ptr3 As LongPtr
Dim ptr4 As LongPtr
Dim ptr5 As LongPtr
Dim ptr6 As LongPtr
Dim ptr7 As LongPtr
Dim ptr8 As LongPtr
Dim ptr9 As LongPtr
'
Dim v As Variant
'
On Error Resume Next
For Each v In c
Next v
Debug.Assert ptr0 = 0
End Sub
버그는 발생하지 않는다. 달리기랑 요?Main2
만의 갈고리로Invoke
모두 ★★★★★★ 。DISP_E_MEMBERNOTFOUND
되며, "No.NewEnum
메서드가 호출됩니다.
앞에서 설명한 콜스택을 나란히 보면 다음과 같습니다.
VB 'VB' VB'가Invoke
의 「 코드 되지 .
own ).VBA는 VBA의 Invoke의 New Enum ID를 사용합니다. (원래 IDispatch:: VB 의 경우와 ). NewEnum하지 않고 하면 버그가 .은 「」 「 NewEnum 」 「NewEnum 」의 경우와 .Main3
위를 하지 않습니다.For Each...
VBA ★★★
버그의 원인
위의 모든 예에서 알 수 있듯이 이 버그는 다음과 같이 요약할 수 있습니다.
For Each
®IDispatch::Invoke
시시 which which which라고 부른다.NewEnum
는, 「스택 포인터」의 .ShowBug
(발신자 「」, 「」(「」)에 의해서 같은 됩니다.ShowBug
착신측 " " " "NewEnum
를 참조해 주세요.
회피책
스택 포인터의 올바른 인크리먼트를 강제하는 방법:
- 을 직접
For Each
( 선 ) 、Sin 1
- 으로 다른
For Each
★★★★★- 의 콜
IUnknown::AddRef
ByVal
- 의 콜
IUnknown::QueryInterface
를stdole.IUnknown
- , 「」의
Set
를 하는 문AddRef
★★★★★★★★★★★★★★★★★」Release
둘 다 또둘둘((((((((((:Set c = c
를 호출할 도 있습니다.QueryInterface
.
- 의 콜
질문의 '편집' 섹션에서 제안했듯이 Custom Collection 클래스를 통과할 수 있는 가능성이 항상 있는 것은 아닙니다.ByVal
변수 또는 일 수 , 더미 ''를 실행할 필요가 있기 때문입니다.Set
For Each...
행됩니니다다
솔루션
질문에서 제시한 것보다 더 나은 해결책을 찾을 수 없었기 때문에 약간의 수정으로 코드를 복제해 보겠습니다.
EnumHelper
링크:
VERSION 1.0 CLASS
BEGIN
MultiUse = -1 'True
END
Attribute VB_Name = "EnumHelper"
Attribute VB_GlobalNameSpace = False
Attribute VB_Creatable = False
Attribute VB_PredeclaredId = False
Attribute VB_Exposed = False
Option Explicit
Private m_enum As IEnumVARIANT
Public Property Set EnumVariant(newEnum_ As IEnumVARIANT)
Set m_enum = newEnum_
End Property
Public Property Get EnumVariant() As IEnumVARIANT
Attribute EnumVariant.VB_UserMemId = -4
Set EnumVariant = m_enum
End Property
Public Property Get Self() As EnumHelper
Set Self = Me
End Property
CustomCollection
제음음하다
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 Sub
Public Sub Add(v As Variant)
m_coll.Add v
End Sub
Public Function NewEnum() As EnumHelper
With New EnumHelper
Set .EnumVariant = m_coll.[_NewEnum]
Set NewEnum = .Self
End With
End Function
요.For Each v in c.NewEnum
,는EnumHelper
클래스는 커스텀 컬렉션 클래스를 구현하는 프로젝트에서 추가 클래스가 필요합니다.또한 몇 가지 장점이 있습니다.
- 해서 꼭 요.
Attribute [MethodName].VB_UserMemId = -4
다른 커스텀 컬렉션 클래스로 이동합니다.이는 RubberDuck을 설치하지 않은 사용자에게 더욱 유용합니다('@Enumerator
하여 커스텀 .cls는 .cls를 사용합니다. - EnumHelper로 지정됩니다.이치노당신은 그것을 가질 수 있다
ItemsEnum
a. a. a.KeysEnum
다요. 둘 다.For Each v in c.ItemsEnum
★★★★★★★★★★★★★★★★★」For Each v in c.KeysEnum
것이다 - 중 .
EnumHelper
호출됩니다.Invoke
멤버 ID -4 is is 、 ID - 4 - 당신은 더 이상 사고를 당하지 않을 것입니다.""로
For Each v in c.NewEnum
그 and를 사용합니다.For Each v in c
런타임 오류만 발생하며 테스트에서 확인될 수 있습니다.까지는 '크래시'의 시켜 강제 크래시를 수.c.NewEnum
방법으로ByRef
음음음음음 a a a a a a a a a a a a a a a a a a a a a a a a a a a a를 해야 합니다.For Each
또는 다른 메서드 호출Set
리는 없겠지 - 언급할 가 있는 것은 한다는 것입니다.
EnumHelper
내의 의 클래스
repair가 부족해서 코멘트를 추가할 수도 없고, frozen이라 채팅창을 사용할 수도 없습니다만, 여기서 제시한 솔루션 중 어느 것도 테스트하지 않았지만, 같은 버그인 것 같습니다.
여기서 설명하려고 했습니다.
테스트에 의해서도 문제가 해결되기를 희망하고 있습니다.그렇다면 문제를 조사하고 64비트 VBA에 코드를 이식할 수 없었던 것에 대한 회피책을 제공해 주셔서 진심으로 감사드립니다.
언급URL : https://stackoverflow.com/questions/63848617/bug-with-for-each-enumeration-on-x64-custom-classes
'programing' 카테고리의 다른 글
셸 스크립트의 행 끝에 세미콜론이 필요합니까? (0) | 2023.04.11 |
---|---|
XlsxWriter로 쓴 후 셀에 형식 적용 (0) | 2023.04.11 |
VB 코드에서 VBProject 보호 해제 (0) | 2023.04.11 |
Bash에서 명령줄 인수를 변경하려면 어떻게 해야 합니까? (0) | 2023.04.11 |
Javascript 내보내기 CSV 인코딩 utf-8 문제 (0) | 2023.04.11 |