Как обработать "несоответствие типов" в массиве VBA логическое / LongLong? - PullRequest
0 голосов
/ 04 февраля 2019

При попытке выполнить приведенный ниже код я получаю сообщение об ошибке VBA: несоответствие типов.Кто-нибудь знает причину (и решение?: -))

Я изменил типы данных с Long на LongLong, чтобы иметь возможность обрабатывать большие числа.До этого код (отрывок) работал нормально.

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 y As LongLong
Dim Max As LongLong
Dim Min As LongLong

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

Dim Arr() As Boolean   'Default Boolean type is False
ReDim Arr(Min To Max) ''<<< "Type Mismatch" compile error

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

End Sub

Конечно, этот код ни к чему не приводит, только для тестирования этого куска кода.

1 Ответ

0 голосов
/ 04 февраля 2019

tldr;

Вы не можете "обработать" это - LongLong не совместимо с вашим утверждением ReDim.(Хотя 999999999 технически вписывается в Long, компилятор не допускает там сужающего преобразования).


Максимальный размер любого массива в VBA определяется SAFEARRAY структура (определена в разделе 2.2.30.10 спецификации OLE Automation Protocol), для которой она поддерживается внутренне.Определение структуры в C ++ таково:

typedef struct tagSAFEARRAY {
  USHORT         cDims;
  USHORT         fFeatures;
  ULONG          cbElements;
  ULONG          cLocks;
  PVOID          pvData;
  SAFEARRAYBOUND rgsabound[1];
}

Обратите внимание, cbElements размер в байтах элемента массива.Это эффективно ограничивает каждый элемент до ~ 4 ГБ.


Проблема, с которой вы столкнулись, заключается в SAFEARRAYBOUND структурах , которые хранят информацию о размерах массива:

typedef struct tagSAFEARRAYBOUND {
  ULONG cElements;
  LONG  lLbound;
} SAFEARRAYBOUND, *LPSAFEARRAYBOUND;

Это означает, что максимальное количество элементов, которое вы можете втиснуть в любое измерение SAFEARRAY независимо от языка программирования, равно ULONG_MAX (4 294 967 295).Таким образом, следующие компиляции (хотя на моей машине не хватает памяти при выделении):

Dim foo(-2147483646 To 2147483647) As Byte

Обратите внимание, что в приведенном выше примере нижняя граница отрицательна, поскольку VBA также не поддерживает неподписанные типы,что представляет собой другое препятствие для кода VBA, который определяет размеры массивов.Технически вы можете получить массив с границами 0 To 4294967294, запросив его через функцию SafeArrayCreate , экспортированную oleaut32.dll, но я подозреваю, что вы столкнетесь с подобными проблемами при индексации.


Сняв слои еще дальше, вы начинаете преодолевать некоторые из наиболее интересных пределов.Например, оглядываясь на структуру SAFEARRAYBOUND выше, вы заметите, что, хотя у вас может быть ULONG_MAX элементов , нижняя граница массива ограничена знаком LONG.Это ограничение переносится на большинство других OLE-автоматов, которые занимаются обработкой SAFEARRAY с, включая SafeArrayGetLBound и другие (интересно, что SafeArrayGetUBound - это также подписано, что заставляет меня задуматься, не могли бы вы переполнить его ...).


Так почему же MS не обновили это, когда добавили 64-битную поддержку?Ну, это сломало бы в значительной степени все .Кроме того, на самом деле не было никакой насущной необходимости - как только вы выйдете за пределы ULONG элементов, вы начнете сталкиваться с очень реальными проблемами с памятью в том, что память для области данных должна быть выделена , когдаструктура создана - в противном случае ее невозможно использовать через COM, поскольку в корне этой структуры находится указатель, а в контракте говорится, что вызывающий код (независимо от клиента) должен иметь возможность использовать любой адрес, попадающий вобласть данных, включая VBA.

...