【问题标题】:How to read/write memory on Mac OS X with VBA?如何使用 VBA 在 Mac OS X 上读/写内存?
【发布时间】:2018-01-27 02:41:15
【问题描述】:

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

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

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

【问题讨论】:

标签: vba macos winapi declare kernel32


【解决方案1】:

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 位/64 位计算机上工作。它还演示了声明和调用函数的两种不同方式(通过指针和通过变量)。

#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

说明:

Mac 版本的 CopyMemory 函数返回结果,而 Win 版本不返回。 (结果是 dest 指针,除非发生错误。请参阅 memmove 引用 here。)但是,两个版本都可以以完全相同的方式使用,无需括号。

声明的区别如下:

  • 64 位 Mac/Win VBA7:

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

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

    • 没有PtrSafe关键字
    • 所有ByRef参数使用Any类型
    • ByVal句柄/指针参数/返回值使用Long类型
    • 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

*正确的方式。

【讨论】:

  • 非常清楚,但我认为这些有点过分:您检查#If VBA7 - 这确保定义了LongPtr。则无需检查#If Win64Private Declare PtrSafe Sub CopyMemory_byPtr Lib "kernel32" Alias "RtlMoveMemory" (ByVal dest As LongPtr, ByVal src As LongPtr, ByVal size As LongPtr) 适用于 32 位和 64 位系统。此外,在您的 Mac 声明中,您在 64 位上使用 Long - 这是正确的吗?对于 Windows,RtlMoveMemory 中的 size/lengthSIZE_T 类型,它是 ULONG_PTR 的别名 - 即 VBA 应该使用 LongPtr - 对于 Mac 的 memmove 也是如此?
【解决方案2】:

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

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

原始/更快的版本是void* memcpy(void *restrict dst, const void *restrict src, size_t n),它不处理重叠的内存区域。

请联系man memmove 了解详情。

【讨论】:

  • 您如何从 VBA 访问 memmove/memcpy?我假设 OP 正在编写用于 Windows 和 Mac OS X 的 VBA 宏,或者将脚本从 Windows 移植到 Mac OS X。
  • 是的,RtlMoveMemorymemmove 的公共包装器。 memcpy 的等价物将是 RtlCopyMemory。但是,问题是为什么您需要这样做。人们在 VBA 中使用RtlMoveMemory 与 Windows API 进行交互。如果您正在与 Cocoa API 交互,您可能应该调用 Cocoa 内存管理函数而不是低级标准库函数。
猜你喜欢
  • 2017-07-30
  • 2012-04-08
  • 2012-02-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-12-25
  • 1970-01-01
相关资源
最近更新 更多