如何使用 VBA read/write Mac OS X 上的内存?

How to read/write memory on Mac OS X with VBA?

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

Private Declare PtrSafe Sub RtlMoveMemory Lib "kernel32" ( _
                              ByVal dest As LongPtr, _
                              ByVal src As LongPtr, _
                              ByVal size As LongPtr)

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

我在 msdn.microsoft.com 上查找了 RtlMoveMemory(),它似乎只是将一些字节从一个地址复制到另一个地址,处理重叠内存的特殊情况。

达尔文等价物是void* memmove(void *dst, const void *src, size_t len)

primitive/faster 版本是 void* memcpy(void *restrict dst, const void *restrict src, size_t n),它不处理重叠内存区域。

做一个man memmove了解详情。

What is the equivalent on 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

长答案:取决于 ;)


以下是一个完整的示例,它使用条件编译*使其可以在任何 Mac/Windows/32-bit/64-bit 计算机上运行。它还演示了声明和调用函数的两种不同方式(通过指针和通过变量)。

#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

解释:

CopyMemory 函数的 Mac 版本 return 是结果,而 Win 版本则不是。 (结果是 dest 指针,除非发生错误。请参阅 memmove 参考 here。)然而,这两个版本可以完全相同的方式使用,没有括号。

声明差异如下:

  • 64 位 Mac/Win VBA7:

    • 使用PtrSafe关键字
    • 所有ByRef参数使用Any类型
    • 使用 LongPtr 类型作为 ByVal handle/pointer parameters/return 值
    • 对其他 return values/parameter
    • 适当使用 LongLong 类型
  • 32 位 Win VBA7:

    • 使用PtrSafe关键字
    • 所有ByRef参数使用Any类型
    • 使用 LongPtr 类型作为 ByVal handle/pointer parameters/return 值
    • 使用 Long (not LongLong) 适当地输入其他 return values/parameter
  • 32 位 Mac/Win VBA6:

    • 没有PtrSafe关键字
    • 所有ByRef参数使用Any类型
    • ByVal handle/pointer parameters/return 值使用 Long 类型
    • 对其他 return values/parameter
    • 适当使用 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 个继续复制 byte.


注意:如果你对我的变量命名规则感到好奇,它是基于 RVBA.

*正确的方式。