当尝试执行以下代码时,我得到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
当然,这段代码没有任何结果,只是为了测试这段代码。
tldr
您无法"处理"它——LongLong
与您的ReDim
语句不兼容。(尽管999999999
在技术上适合Long
,但编译器不允许在那里进行缩小转换)。
VBA中任何数组的最大大小由内部支持的SAFEARRAY
结构(在OLE自动化协议规范的2.2.30.10节中定义)决定。C++中结构的定义是:
typedef struct tagSAFEARRAY { USHORT cDims; USHORT fFeatures; ULONG cbElements; ULONG cLocks; PVOID pvData; SAFEARRAYBOUND rgsabound[1]; }
注意,cbElements
是数组项的字节大小。这有效地将每个项目限制在约4GB。
您遇到的问题是存储有关数组维度信息的SAFEARRAYBOUND
结构:
typedef struct tagSAFEARRAYBOUND { ULONG cElements; LONG lLbound; } SAFEARRAYBOUND, *LPSAFEARRAYBOUND;
这意味着,无论编程语言如何,您都可以塞进SAFEARRAY
的任何维度的最大项目总数是ULONG_MAX
的值(4294967295)。因此,以下编译(尽管它在我的机器上的分配耗尽了内存):
Dim foo(-2147483646 To 2147483647) As Byte
请注意,在上例中,下限为负数,因为VBA也不支持无符号类型,这为VBA代码调整数组大小带来了另一个障碍。从技术上讲,你可以通过oleout32.dll导出的SafeArrayCreate函数请求一个边界为0 To 4294967294
的数组,但我怀疑你在索引它时会遇到类似的问题。
将图层向后剥离,您开始达到一些更有趣的极限。例如,回顾上面的SAFEARRAYBOUND
结构,您会注意到,尽管您可以拥有ULONG_MAX
元素,但数组的下界受到符号LONG
的约束。这一限制被转移到大多数其他处理SAFEARRAY
的OLE自动化中,包括SafeArrayGetLBound
和其他(有趣的是,SafeArrayGetUBound
也是签名的,这让我怀疑你是否可以溢出它…)
为什么MS在添加64位支持时没有更新?好吧,它几乎会破坏所有。除此之外,真的没有任何迫切的需要-一旦你超过了ULONG
元素,你就会开始遇到非常实际的内存问题,因为在创建结构时必须分配数据区域的内存-否则就不可能通过COM使用它,因为该结构的根是一个指针,合同规定,调用代码(无论客户端如何)必须能够使用数据区域内的任何地址,包括VBA。