我在VBA中创建了一个类,该类旨在监视变量直到更改。该类异步运行; Windows Timer API大约每秒钟调用Tick
方法-类似于Application.OnTime
Option Explicit
Public Event Tick()
Public Event Complete()
Private Type tTimer
tickFrequency As Double 'in seconds
conditionMet As Boolean
End Type
Private this As tTimer
Public Sub await(ByRef waitUntil As Boolean, Optional ByVal tickFrequency As Double = 1)
this.conditionMet = waitUntil 'only creates a copy, doesn't point to the same variable
startTicking tickFrequency, Me
End Sub
Public Sub Tick()
If this.conditionMet Then 'If initially False then will never be updated to True
stopTicking
RaiseEvent Complete
Else
RaiseEvent Tick
End If
End Sub
Private Sub Class_Terminate()
stopTicking
End Sub
称呼为
Dim someCondition As Boolean
'evaluate condition
await someCondition, 0.5 'check back every half a second
'continue other processes which may alter the value of someCondition
该想法是通过条件byRef
,以便可以在每个刻度上监视更改。同时,其他异步运行的代码(例如工作表上的按钮)可以根据需要编辑变量的值。
我能想到一些解决方法;
waitUntil
公开为该类的公共变量,以便调用者代码可以直接将其写入但是,这两个步骤都需要我不想在呼叫方执行的其他步骤。
我想知道我是否可以对VarPtr
进行一些欺骗-如果我正确理解的话,它将在传递的byRef
变量的内存中返回一个地址。因此,通过在我的班级中保存该地址的副本,我可以在需要时在该位置查找变量。但是我不知道该怎么做,也不能简洁地表达这个问题以进行搜索!
答案 0 :(得分:0)
一种方法,如我所提到的,是使用VarPtr
函数来查找值。 CopyMemory Api方法将查找地址中的值移动到新变量。
Private Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (dest As _
Any, source As Any, ByVal bytes As Long)
' read a value of any type from memory
Function Peek(ByVal address As Long, ByVal ValueType As VbVarType) As Variant
Select Case ValueType
Case vbByte
Dim valueB As Byte
CopyMemory valueB, ByVal address, 1
Peek = valueB
Case vbInteger
Dim valueI As Integer
CopyMemory valueI, ByVal address, 2
Peek = valueI
Case vbBoolean
Dim valueBool As Boolean
CopyMemory valueBool, ByVal address, 2
Peek = valueBool
Case vbLong
Dim valueL As Long
CopyMemory valueL, ByVal address, 4
Peek = valueL
Case vbSingle
Dim valueS As Single
CopyMemory valueS, ByVal address, 4
Peek = valueS
Case vbDouble
Dim valueD As Double
CopyMemory valueD, ByVal address, 8
Peek = valueD
Case vbCurrency
Dim valueC As Currency
CopyMemory valueC, ByVal address, 8
Peek = valueC
Case vbDate
Dim valueDate As Date
CopyMemory valueDate, ByVal address, 8
Peek = valueDate
Case vbVariant
' in this case we don't need an intermediate variable
CopyMemory Peek, ByVal address, 16
Case Else
Err.Raise 1001, , "Unsupported data type"
End Select
End Function
然后可以像这样使用
Public Sub await(ByRef waitUntil As Boolean, Optional ByVal tickFrequency As Double = 1)
this.conditionAddress= VarPtr(waitUntil) 'only creates a copy, doesn't point to the same variable
startTicking tickFrequency, Me
End Sub
Public Sub Tick()
If Peek(this.conditionAddress, vbBoolean) Then 'If initially False then will never be updated to True
stopTicking
RaiseEvent Complete
Else
RaiseEvent Tick
End If
End Sub
每隔Tick
检查一次变量的值