3

I am trying to upgrade my large number VBA application from Long datatype to LongLong or LongPtr to be able to handle more digits. But I can't figure out how to call this PtrSafe Sub... Some assistance would be very helpful.

I tried a simple example Sub to isolate the problem. But don't know which Lib I should call and on top of that: should this Sub be Private or Public?

Public Declare PtrSafe Sub Example Lib "??????" (ByVal x, y, z As LongPtr)

Dim x, y, z As LongPtr

x = 123456789
y = 123456789
MsgBox z = x * y

End Sub

Could anyone explain to me step-by-step how to call a Sub that is PtrSafe?

Pᴇʜ
  • 56,719
  • 10
  • 49
  • 73
Ronald Vonk
  • 73
  • 1
  • 4

2 Answers2

5

PtrSafe

Use the PtrSafe just to enable 32bit API calls on 64bit systems like this:

Private Declare PtrSafe Function GetDC Lib "user32" (ByVal hwnd As LongPtr) As LongPtr
Private Declare PtrSafe Function GetDeviceCaps Lib "gdi32" (ByVal hDC As LongPtr, ByVal nIndex As Long) As Long
Private Declare PtrSafe Function ReleaseDC Lib "user32" (ByVal hwnd As LongPtr, ByVal hDC As LongPtr) As Long

Public Sub TestScreenResolution()
    Debug.Print ScreenResolution
End Sub
Private Function ScreenResolution() As Double
     Dim hDC As LongPtr
     hDC = GetDC(0)
     ScreenResolution = GetDeviceCaps(hDC, 88)
     ReleaseDC 0, hDC
End Function

Conditional Compilation

You may use both via conditional compilation

#If Win64 Then
    Private Declare PtrSafe Function MakeSureDirectoryPathExists _
        Lib "imagehlp.dll" (ByVal DirPath As String) As Boolean
#Else
    Private Declare Function MakeSureDirectoryPathExists Lib _
        "imagehlp.dll" (ByVal DirPath As String) As Boolean
#End If

Your own Sub or Function with 64bit variables

These can be declared like this:

Public Sub TestMySub()
    Call MySub(123456789, 123456789)
End Sub

Private Sub MySub(ByVal x As LongLong, ByVal y As LongPtr)
    Dim z As LongLong
    z = x * y
    MsgBox z
End Sub

I prefer Private as long as possible and Public only if "external" access is needed.

Data types LongLong vs. LongPtr vs. Decimal

On 64bit LongLong and LongPtr are both a "LongLong Integer" with 8 Byte:
-9.223.372.036.854.775.808 to 9.223.372.036.854.775.807

But be aware: But if you use LongLong, it will ONLY work on 64bit, where LongPtr on 32bit would be handled simply as a Long in 4 bytes, which results in
-2.147.483.648 to 2.147.483.647

So if you really need a high value on both systems and Long is not enough, consider to use a Double (8 Bytes, including rounding effects!) or Decimal (14 Bytes, has to be declared as Variant first):

Private Sub DataTypeDecimal()
    ' Decimal only via declaration as Variant and type cast as Decimal
    Dim d As Variant
    d = CDec("79.228.162.514.264.337.593.543.950.335")
    Debug.Print d
    d = CDec("-79.228.162.514.264.337.593.543.950.335")
    Debug.Print d
End Sub
Asger
  • 3,822
  • 3
  • 12
  • 37
  • `to enable 32bit API calls on 64bit systems` - there are no 32-bit API calls on 64-bit systems. They are 64-bit calls there. `PtrSafe` does not enable 32-bit calls, it [asserts](https://stackoverflow.com/a/44785205/11683) that the code has been verified as size-compatible with 64-bit. `#If Win64` is [not the right constant](https://stackoverflow.com/a/56940710/11683) to use either, it's `#If VBA7`. – GSerg Aug 09 '22 at 22:38
-1

The example I gave you is working allright, thank you for this :-).

The real application however now says "type mismatch" at the moment I try to fill Arr(z) with 'True'-Booleans (excerpt) (it worked fine with Long datatype):

Private Declare PtrSafe Function GetDC Lib "user32" (ByVal hwnd As LongPtr) As LongPtr
Private Declare PtrSafe Function GetDeviceCaps Lib "gdi32" (ByVal hDC As LongPtr, ByVal nIndex As Long) As Long
Private Declare PtrSafe Function ReleaseDC Lib "user32" (ByVal hwnd As LongPtr, ByVal hDC As LongPtr) As Long

Public Sub TestScreenResolution()
    Debug.Print ScreenResolution
End Sub
Private Function ScreenResolution() As Double
     Dim hDC As Long
     hDC = GetDC(0)
     ScreenResolution = GetDeviceCaps(hDC, 88)
     ReleaseDC 0, hDC
End Function

Public Sub TestMySub()
    Call MySub(999999999)
End Sub
Private Sub MySub(ByVal x As LongLong)

Dim z As LongLong
Dim Max, Min As LongLong

Max = x * x
Min = (x - 2) * (x - 2)

Dim Arr() As Boolean 'Default Boolean type is False
ReDim Arr(Min To Max)

For z = Max To Min Step -2
    Arr(z) = True
Next z

End Sub
Ronald Vonk
  • 73
  • 1
  • 4
  • Sorry, was busy editing my answer/new questions while you wrote this. But marked your answer as helping anyway :-). – Ronald Vonk Feb 03 '19 at 08:04
  • If you declare `Dim Max, Min As LongLong` Then Max is only a Variant! Declare `Dim Max As LongLong, Min As LongLong` – Asger Feb 03 '19 at 08:16
  • Thanks, I did as you said, but VBA still says "types don't match" at line: ReDim Arr(Min, Max) – Ronald Vonk Feb 03 '19 at 09:01
  • A to B is different from A, B! Post a new question neither in comments nor as answer but ask a new thread please – Asger Feb 03 '19 at 09:15