VBA RtlMoveMemory работает только с ByVal - PullRequest
0 голосов
/ 28 мая 2018

Рабочий код:

Declare PtrSafe Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (pDest As Any, pSource As Any, ByVal ByteLen As Long)

Sub Test()

Dim Long1 As Long
Dim Long2 As Long

    Long1 = 1000
    CopyMemory ByVal VarPtr(Long2), ByVal VarPtr(Long1), 4
    Debug.Print VarPtr(Long1)
    Debug.Print Long2
End Sub

У меня есть два вопроса:

Насколько я понимаю, среда выполнения VB освободила память Long1 и Long2, когда они вышли из области видимости.Почему Debug.Print VarPtr(Long1) возвращает один и тот же адрес при каждом запуске программы?Сохраняет ли VB Runtime определенную часть памяти для переменных?Я верю в это, поскольку даже я что-то сделал (например, закрыл вкладку Chrome), чтобы освободить память из кучи, в которой она хранится, показывать тот же адрес.

Почему мне нужно использовать ByVal, чтобы получить правильный результат?Я понимаю, что CopyMemory просто перемещает количество байтов от адреса , указанного целым числом VarPtr(Long1), до адреса , указанного целым числом VarPtr(Long2), но я неНе знаю, почему я должен использовать ключевое слово ByVal, в противном случае оно просто возвращает 0.Я подумал, что, возможно, VBA принимает ByRef по умолчанию, а с ByRef это означает копирование байтов с адреса, в котором хранится адрес Long1 (в основном ссылка на возвращаемое значение VarPtr, которое является просто целым числом), который является ничем, по адресу, в котором хранится адрес Long2, который также является ничем.Но VBA просто выдает мне сообщение об ошибке, если я намеренно использую ByRef.

1 Ответ

0 голосов
/ 28 мая 2018

Примитивные локальные переменные хранятся в стеке , поэтому адрес зависит от порядка, в котором вы вызываете подпрограмму, вы можете увидеть это на простом примере:

Sub showAdresses()
    myTest
    callTest
    callTest
    myTest
End Sub

Sub callTest()
    myTest
End Sub

Sub myTest()
    Dim x As Long
    Debug.Print VarPtr(x)
End Sub

Youбудет видеть один и тот же адрес для первого и последнего вызова, а другой - для вызовов между ними - просто потому, что в промежуточной подпрограмме требуется место в стеке.Когда подпрограмма завершается, занятое пространство в стеке освобождается и (это характер стека) немедленно повторно используется, поэтому, если вы вызовете ту же самую процедуру снова, та же самая переменная получит тот же адрес (но VBA инициализирует его).

Для ключевого слова ByVal при вызове CopyMemory: я предполагаю, что вызов VarPtr возвращает указатель , и вы передаете указатель в качестве значения- иначе вы передадите адрес указателя.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...