异步监视byRef传递的值

问题描述 投票:1回答:1

我在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的变量的内存地址。因此,通过在我的课程中保存该地址的副本,我可以在需要时在该位置查找变量。但是我不知道如何做到这一点,不能简单地用短语来搜索这个问题!

excel vba excel-vba pointers asynchronous
1个回答
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检查变量的值

© www.soinside.com 2019 - 2024. All rights reserved.