代码之家  ›  专栏  ›  技术社区  ›  Greedo

异步监视byRef传递的值

  •  1
  • Greedo  · 技术社区  · 6 年前

    我在VBA中创建了一个类,用于监视变量,直到它发生变化。类异步运行;Windows计时器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 -如果我理解正确,这将返回传递的变量在内存中的地址 拜里夫 .因此,通过在我的类中保存该地址的副本,我可以随时在该位置查找变量。然而,我不知道如何做到这一点,也不能用足够简洁的措辞来搜索这个问题!

    1 回复  |  直到 6 年前
        1
  •  0
  •   Greedo    6 年前

    正如我提到的,一种方法是使用 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

    推荐文章