Private Declare PtrSafe Function VirtualProtect Lib "kernel32" ( _
ByVal memAddress As LongPtr, _
ByVal lengthInBytes As LongPtr, _
ByVal newProtect As protectFlags, _
ByRef outOldProtect As protectFlags _
) As Long
Public Enum protectFlags 'an enum is a Long in VBA which is 32-bit so can be used in place of DWORD
PAGE_NOACCESS = &H1
PAGE_READONLY = &H2
PAGE_READWRITE = &H4
PAGE_WRITECOPY = &H8
PAGE_EXECUTE = &H10
PAGE_EXECUTE_READ = &H20
PAGE_EXECUTE_READWRITE = &H40
PAGE_EXECUTE_WRITECOPY = &H80
PAGE_GUARD = &H100
PAGE_NOCACHE = &H200
PAGE_WRITECOMBINE = &H400
End Enum
I'm calling it like this:
Dim memoryAddress As LongPtr
memoryAddress = ... 'some protected memory
Dim originalProtection As protectFlags
If CBool(VirtualProtect(memoryAddress, 8, PAGE_EXECUTE_READWRITE, originalProtection)) Then
Debug.Print "Previous protection cached: &H"; Hex(originalProtection)
Else
Err.Raise 5, Description:="Memory address cannot be unprotected with PAGE_EXECUTE_READWRITE"
End If
... I'm then restoring the protection
VirtualProtect(memoryAddress, 8, originalProtection, temp)
The problem is, originalProtection
remains &H0 after the first call, and so in the second call I get LastDllError of 87 - "The parameter is incorrect.". I'm pretty sure the memory is protected originally since removing the call to VirtualProtect crashes my programme, whereas including it is successful. But I can't reset the protection.
For reference this is what I'm translating:
BOOL VirtualProtect(
LPVOID lpAddress,
SIZE_T dwSize,
DWORD flNewProtect,
PDWORD lpflOldProtect
);
Yes the declaration is correct.
The problem was that in my actual code, originalProtection
was a public class variable.
Public class variables cannot be passed ByRef to a function because they are actually implemented under the hood as Property Get/Let procedures with a hidden private variable, and so only a temporary value is passed to VirtualProtect rather than the underlying variable to be written to.
The solution was to declare a local variable with Dim
to receive the value and then to write it to my class variable.