Как читать/записывать память на Mac OS X с помощью 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?

Ответы

Ответ 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-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

Объяснение:

Mac-версия функции CopyMemory возвращает результат, в то время как версия 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-бит.
  • Протестировано в 32-разрядной версии Windows Excel 2007.

    • Похоже, Excel 2007 имеет проблемы, связанные с двойным выравниванием слов. В этом Пример:

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

      CopyMemory() пропускает все копии, пока выравнивание двойного слова не будет (в этом случае 3 прыжка), затем продолжается копирование с 4-го байт.


Примечание. Если вам интересно о моем соглашении об именах переменных, оно основано на RVBA.

* правильный способ.

Ответ 2

Я просмотрел RtlMoveMemory() на msdn.microsoft.com и, похоже, просто скопировал несколько байтов с одного адреса на другой, передав специальный случай перекрывающейся памяти.

эквивалент Дарвина void* memmove(void *dst, const void *src, size_t len)

Примитивная/более быстрая версия void* memcpy(void *restrict dst, const void *restrict src, size_t n), которая не обрабатывает перекрывающиеся области памяти.

Сделайте man memmove для деталей.