Как я могу объявить подписку PtrSafe в VBA? Windows 7, Excel 2016, 64-разрядная версия

Я пытаюсь обновить свое большое приложение VBA с типа данных Long до LongLong или LongPtr, чтобы иметь возможность обрабатывать больше цифр. Но я не могу понять, как назвать эту PtrSafe Sub ... Некоторая помощь была бы очень полезна.

Я попробовал простой пример Sub, чтобы изолировать проблему. Но не знаю, какую библиотеку мне следует вызвать, и, кроме того, должна ли эта подписка быть частной или публичной?

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

Может ли кто-нибудь объяснить мне шаг за шагом, как вызвать подпрограмму, которая является PtrSafe?


person Ronald Vonk    schedule 02.02.2019    source источник


Ответы (2)


PtrSafe

Используйте PtrSafe только для включения 32-битных вызовов API в 64-битных системах, например:

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

Условная компиляция

Вы можете использовать оба через условную компиляцию

#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

Ваша собственная подпрограмма или функция с 64-битными переменными

Их можно объявить так:

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

Я предпочитаю Private как можно дольше и Public только если нужен "внешний" доступ.

Типы данных LongLong vs. LongPtr vs. Decimal

На 64-битной версии LongLong и LongPtr представляют собой «длинное целое число» с 8 байтами:
от -9.223.372.036.854.775.808 до 9.223.372.036.854.775.807

Но имейте в виду: но если вы используете LongLong, он будет работать ТОЛЬКО на 64-битной версии, где LongPtr на 32-битной версии будет обрабатываться просто как Long в 4 байтах, что приводит к от -2.147.483.648 до 2.147.483.647

Поэтому, если вам действительно нужно высокое значение в обеих системах, а Long недостаточно, подумайте об использовании Double (8 байтов, включая эффекты округления!) Или Decimal (14 байтов, сначала нужно объявить как Variant):

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
person Asger    schedule 02.02.2019

Пример, который я вам привел, работает нормально, спасибо за это :-).

Настоящее приложение, однако, теперь говорит «несоответствие типов», в тот момент, когда я пытаюсь заполнить Arr (z) логическими значениями True (отрывок) (оно отлично работало с типом данных Long):

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
person Ronald Vonk    schedule 03.02.2019
comment
Извините, я был занят редактированием моего ответа / новых вопросов, пока вы это писали. Но все равно пометил ваш ответ как помогающий :-). - person Ronald Vonk; 03.02.2019
comment
Если вы объявите Dim Max, Min As LongLong, тогда Макс будет только вариантом! Объявить Dim Max As LongLong, Min As LongLong - person Asger; 03.02.2019
comment
Спасибо, я сделал, как вы сказали, но VBA по-прежнему говорит, что типы не совпадают в строке: ReDim Arr (Min, Max) - person Ronald Vonk; 03.02.2019
comment
От A до B отличается от A, B! Не публикуйте новый вопрос ни в комментариях, ни в качестве ответа, но задавайте новую тему, пожалуйста - person Asger; 03.02.2019