如何处理VBA布尔/长数组中的“类型不匹配”?

时间:2019-02-04 15:59:25

标签: arrays vba long-long

当尝试执行以下代码时,出现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 :(得分:6)

tldr;

您无法“处理”它-LongLong与您的ReDim语句不兼容。 (尽管999999999在技术上适合Long,但编译器不允许在那里进行缩小转换。)


VBA中任何数组的最大大小由内部支持的SAFEARRAY structure(在OLE自动化协议规范的section 2.2.30.10中定义)确定。 C ++中的结构定义是这样的:

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

请注意,cbElements的大小以字节为单位表示数组项。这有效地将每个项目限制为〜4GB。


您遇到的问题是在SAFEARRAYBOUND structures中,它存储有关数组维的信息:

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

这意味着无论编程语言如何,您可以塞入SAFEARRAY any 维度的项目总数的最大值是ULONG_MAX的值(4,294,967,295)。因此,将编译以下内容(尽管由于我的计算机上的分配而耗尽了内存):

Dim foo(-2147483646 To 2147483647) As Byte

请注意,在上面的示例中,下限为负,因为VBA还不支持无符号类型,这为调整数组大小的VBA代码提供了另一个障碍。从技术上讲,您可以通过oleaut32.dll导出的SafeArrayCreate函数来请求一个边界为0 To 4294967294的数组,但是我怀疑您在索引该索引时会遇到类似的问题。


将图层进一步剥离,您便开始遇到一些更有趣的限制。例如,回顾上面的SAFEARRAYBOUND结构,您会发现尽管可以使用ULONG_MAX elements ,但是数组的下限受约束。 > 签名 LONG。该限制被延续到处理SAFEARRAY的大多数其他OLE自动化中,包括SafeArrayGetLBound和其他{有趣的是,SafeArrayGetUBound也已 签名,这让我想知道是否会溢出...)。


那么当他们添加64位支持时,MS为什么不更新它呢?好吧,它会破坏几乎所有的东西。除此之外,确实没有任何紧迫的需求-一旦您超出ULONG元素,就会开始遇到内存的非常实际的问题,因为数据区域的内存必须要在创建结构时进行分配-否则无法通过COM使用它,因为在该结构的根部是一个指针,并且合同规定调用代码(无论客户端如何)都必须能够使用属于数据区域(包括VBA)。

相关问题