如何使用VBA在Mac OS X上读/写内存?

mic*_*ael 15 macos winapi vba declare kernel32

在Windows上,声明的函数RtlMoveMemory提供了一种将字节块从一个地址复制到另一个地址的方法:

Private Declare PtrSafe Sub RtlMoveMemory Lib "kernel32" ( _
                              ByVal dest As LongPtr, _
                              ByVal src As LongPtr, _
                              ByVal size As LongPtr)
Run Code Online (Sandbox Code Playgroud)

Mac OS X上的等价物是什么?

rob*_*CTS 6

Mac OS X上的等价物是什么?

简短回答:

Private Declare PtrSafe Function CopyMemory Lib "libc.dylib" Alias "memmove" _
                                 ( _
                                    ByVal dest As LongPtr _
                                  , ByVal src As LongPtr _
                                  , ByVal size As LongLong _
                                  ) _
                        As LongPtr
Run Code Online (Sandbox Code Playgroud)

答案很长:取决于;)


以下是一个完全成熟的示例,它使用条件编译*使其可以在任何Mac/Windows/32位/ 64位计算机上运行.它还演示了声明和调用函数的两种不同方式(通过Pointer和Variable).

#If Mac Then
  #If Win64 Then
    Private Declare PtrSafe Function CopyMemory_byPtr Lib "libc.dylib" Alias "memmove" (ByVal dest As LongPtr, ByVal src As LongPtr, ByVal size As Long) As LongPtr
    Private Declare PtrSafe Function CopyMemory_byVar Lib "libc.dylib" Alias "memmove" (ByRef dest As Any, ByRef src As Any, ByVal size As Long) As LongPtr
  #Else
    Private Declare Function CopyMemory_byPtr Lib "libc.dylib" Alias "memmove" (ByVal dest As Long, ByVal src As Long, ByVal size As Long) As Long
    Private Declare Function CopyMemory_byVar Lib "libc.dylib" Alias "memmove" (ByRef dest As Any, ByRef src As Any, ByVal size As Long) As Long
  #End If
#ElseIf VBA7 Then
  #If Win64 Then
    Private Declare PtrSafe Sub CopyMemory_byPtr Lib "kernel32" Alias "RtlMoveMemory" (ByVal dest As LongPtr, ByVal src As LongPtr, ByVal size As LongLong)
    Private Declare PtrSafe Sub CopyMemory_byVar Lib "kernel32" Alias "RtlMoveMemory" (ByRef dest As Any, ByRef src As Any, ByVal size As LongLong)
  #Else
    Private Declare PtrSafe Sub CopyMemory_byPtr Lib "kernel32" Alias "RtlMoveMemory" (ByVal dest As LongPtr, ByVal src As LongPtr, ByVal size As Long)
    Private Declare PtrSafe Sub CopyMemory_byVar Lib "kernel32" Alias "RtlMoveMemory" (ByRef dest As Any, ByRef src As Any, ByVal size As Long)
  #End If
#Else
  Private Declare Sub CopyMemory_byPtr Lib "kernel32" Alias "RtlMoveMemory" (ByVal dest As Long, ByVal src As Long, ByVal size As Long)
  Private Declare Sub CopyMemory_byVar Lib "kernel32" Alias "RtlMoveMemory" (ByRef dest As Any, ByRef src As Any, ByVal size As Long)
#End If


Public Sub CopyMemoryTest()

  Dim abytDest(0 To 11) As Byte
  Dim abytSrc(0 To 11) As Byte
  Dim ¡ As Long

  For ¡ = LBound(abytSrc) To UBound(abytSrc)
    abytSrc(¡) = AscB("A") + ¡
  Next ¡

  MsgBox "Dest before copy = #" & ToString(abytDest) & "#"
  CopyMemory_byVar abytDest(0), abytSrc(0), 4
  MsgBox "Dest during copy = #" & ToString(abytDest) & "#"
  CopyMemory_byPtr VarPtr(abytDest(0)) + 4, VarPtr(abytSrc(0)) + 4, 4
  MsgBox "Dest during copy = #" & ToString(abytDest) & "#"
  CopyMemory_byPtr VarPtr(abytDest(8)), VarPtr(abytSrc(8)), 4
  MsgBox "Dest after copy = #" & ToString(abytDest) & "#"

End Sub

Public Function ToString(ByRef pabytBuffer() As Byte) As String
  Dim ¡ As Long
  For ¡ = LBound(pabytBuffer) To UBound(pabytBuffer)
    ToString = ToString & Chr$(pabytBuffer(¡))
  Next ¡
End Function
Run Code Online (Sandbox Code Playgroud)

说明:

CopyMemory函数的Mac版本返回结果,而Win版本则不返回.(结果是dest指针,除非发生错误.请参阅此处的memmove参考.)但是,两个版本的使用方式完全相同,无括号.

声明的差异如下:

  • 64位Mac/Win VBA7:

    • 使用PtrSafe关键字
    • Any所有 ByRef参数使用类型
    • 使用LongPtr类型ByVal句柄/指针参数/返回值
    • LongLong适当地使用该类型用于其他返回值/参数
  • 32位Win VBA7:

    • 使用PtrSafe关键字
    • Any所有 ByRef参数使用类型
    • 使用LongPtr类型ByVal句柄/指针参数/返回值
    • 对其他返回值/参数适当使用Long( LongLong)类型
  • 32位Mac/Win VBA6:

    • 没有PtrSafe关键字
    • Any所有 ByRef参数使用类型
    • 使用Long类型ByVal句柄/指针参数/返回值
    • Long适当地使用该类型用于其他返回值/参数

注意事项:

  • 在Mac Excel 2016 64位上测试.
  • 在Windows Excel 2007 32位上测试.

    • 似乎Excel 2007存在与双字对齐相关的问题.在这个例子中:

      CopyMemory_byVar abytDest(0), abytSrc(0), 4 '-> ABCD CopyMemory_byVar abytDest(1), abytSrc(1), 8 '-> ABCDEFGHI

      CopyMemory() 跳过所有复制,直到达到双字对齐(在这种情况下为3次跳过),然后从第4个字节继续复制.


注意:如果您对我的变量命名约定感到好奇,那么它基于RVBA.

*正确的道路.