3
votes

Updated Please see the last part of the question for updates

Full source-code here:

https://www.planet-source-code.com/vb/scripts/ShowCode.asp?txtCodeId=30761&lngWId=1

I have a piece of code that does not work, probably due to 32-bit and 64-bit difference:

Part of the code: (I added the PtrSafe, which I shouldn't for the first one)

Private Declare PtrSafe Function ArrPtr& Lib "msvbvm60.dll" Alias "VarPtr" (ptr() As Any)
Private Declare PtrSafe Sub RtlMoveMemory Lib "kernel32" (dst As Any, src As Any, ByVal nBytes&)

Private Header1(5) As Long
Private Header2(5) As Long
Private SafeArray1() As Integer
Private SafeArray2() As Integer
Private LUT(8482) As Long

Private Sub Class_Initialize()
    Dim i As Long

    ' Set up our template for looking at strings
    Header1(0) = 1              ' Number of dimensions
    Header1(1) = 2              ' Bytes per element (integer = 2)
    Header1(4) = &H7FFFFFFF     ' Array size, 2.1+ billion should cover us

    ' Force SafeArray1 to use Header1 as its own header
    RtlMoveMemory ByVal ArrPtr(SafeArray1), VarPtr(Header1(0)), 4

I googled for sometime, found out that msvbvm60.dll seems to be the old 32-bit VBA and has been replaced with VBA7.dll. Tried to re-register the file as it is in SysWOW64 folder, after which VBE still reports that cannot find this file. So I commented the first line, and changed the last line to:

RtlMoveMemory ByVal VarPtr(SafeArray1), VarPtr(Header1(0)), 4

As I believe ArrPtr is simply VarPtr with an alias.

Now I get a type mismatch error. What I understand is that the code points the header of SafeArray1 to the address of Header1(0). I assume that it means that SafeArray1[0]~SafeArray[9] should contain the info in Header1(0)~Header1(4) as Header1() is Long and SafeArray() is Integer? But shouldn't VarPtr returns Long in 32-bit Office and how come it is possible to use it on an Integer array?

But the point is how to make it run on 64-bit Office. Since VarPtr now returns LongPtr instead of Long, I'm not sure how to modify the code.

Updates I found another piece of code that gives me pointer to an array:

Private Declare PtrSafe Function VarPtrArray Lib "VBE7" Alias _
    "VarPtr" (ByRef Var() As Any) As LongPtr

Then I write a test module:

Private Declare PtrSafe Function VarPtrArray Lib "VBE7" Alias _
        "VarPtr" (ByRef Var() As Any) As LongPtr
Private Declare PtrSafe Sub RtlMoveMemory Lib "kernel32" (dst As Any, src As Any, ByVal nBytes&)
Private Header1(5) As Long
Private SafeArray1() As Integer

Sub test()

    Header1(0) = 1              ' Number of dimensions
    Header1(1) = 2              ' Bytes per element (integer = 2)
    Header1(4) = &H7FFFFFFF     ' Array size, 2.1+ billion should cover us

    RtlMoveMemory ByVal VarPtrArray(SafeArray1), VarPtr(Header1(0)), 4
    Debug.Print SafeArray1(0)

End Sub

But VBE crashes on the RtlMoveMemory line.

2
As you mentioned, using LongPtr makes it safe for 32bit as Long but 64bit as a LongLong. What is an integer array? everything is Long. I don't think I understand what you're running into or why you need those alias functions?Raystafarian
@Raystafarian Thanks, actually it is someone else's code, the original link is at the top of the post. I have no idea why he did that and assume that it has something to do with speed as VBA is very slow about string operations.Nicholas Humphrey
@Raystafarian Please see the test module I updated at the end of the post. Thanks for pointing me to that MSDN article as it mentions "VBA converts all integer values to type Long, even if they're declared as type Integer". I guess that's the reason for Type Mismatch? Because LongPtr returns LongLong while Header and SafeArray are both Long Array (Integer is converted to Long).Nicholas Humphrey
1. "Does not work" means nothing. Please don't ever write this. Instead post the error or explain the issue. 2. This looks like cargo cult programming. If you are running a solution built in VBA with performance issues, the answer is not to continue using esoteric DLL's, I do suggest you understand the actual requirement further and rebuild in a more appropriate platform. I understand that commercial realities mean this may not be an option but you should consider it.Nick.McDermaid

2 Answers

2
votes

The following example should show how to handle Declare statement for 32 and 64 bit versions:

Option Explicit

#If VBA7 Then '64 bit
     Private Declare PtrSafe Function DrawMenuBar Lib "User32" (ByVal hwnd As LongPtr) As LongPtr
#Else '32 bit
    Private Declare Function DrawMenuBar Lib "User32" (ByVal hwnd As Long) As Long
#End If
1
votes

on the crash issue, I noticed this line:

RtlMoveMemory ByVal VarPtrArray(SafeArray1), VarPtr(Header1(0)), 4

The last argument should be "long" as declared, so try to put "4" in a long variable and pass it to the function. This is my workaround for my own similar case, and hope that helps.