我想了解SAFEARRAY的实施情况。
在我看来,SAFEARRAY结构中没有用于存储元素类型信息的字段,例如VT_I4(3)或VT_R4(4),但SafeArrayGetVartype函数返回正确的类型。
有人在下面的MSDN页面上发表评论说cLocks
的高位词包含类型信息:SAFEARRAY structure on MSDN
但是当我通过类型libray将Long和Single数组从VBA传递给DLL函数时,那些数组的fFeatures都是0x80,cLocks都是0,而stll SafeArrayGetVartype可以告诉VT_I4(3)和VT_R4(4)。
答案 0 :(得分:4)
根据safearray的创建方式,变体类型可以存储在内存中(从SAFEARRAY
结构开始的偏移-4处)。 FADF_HAVEVARTYPE
中的fFeatures
标志表示该类型是否可用。
同样,FADF_HAVEIID
表示GUID(请参阅SafeArrayCreateEx
)存储在-16的偏移量处,并可通过SafeArrayGetIID
获得。 FADF_HAVEVARTYPE
和FADF_HAVEIID
永远不会同时出现(因为VARTYPE
和GUID
会在内存中重叠),但SafeArrayGetVartype
足够智能合成一个当VT_RECORD
,VT_DISPATCH
或VT_UNKNOWN
类型看到相应的功能标记时,它们会显示。
答案 1 :(得分:2)
您永远不会手动初始化SAFEARRAY
,它始终是调用SafeArrayCreate
的产品,它为此结构分配内存。我认为假设为SafeArray的内部数据结构分配了一些额外的字节是安全的。这就是可以存储任何扩展类型信息的地方。
答案 2 :(得分:2)
要进一步扩展SAFEARRAY
var类型的存储位置,并探究SafeArrayGetVartype
函数和其他SafeArray
函数的作用,请参见:
/* Memory Layout of a SafeArray:
*
* -0x10: start of memory.
* -0x10: GUID for VT_DISPATCH and VT_UNKNOWN safearrays (if FADF_HAVEIID)
* -0x04: DWORD varianttype; (for all others, except VT_RECORD) (if FADF_HAVEVARTYPE)
* -0x4: IRecordInfo* iface; (if FADF_RECORD, for VT_RECORD (can be NULL))
* 0x00: SAFEARRAY,
* 0x10: SAFEARRAYBOUNDS[0...]
*/
对于以下使用MS Access VBA 7的整数数组声明,其中地址引用的大小为8个字节。
Dim myArray() As Integer
ReDim myArray(9)
Pos Address Dec Address Hex Hex
0 (1185248224) (46A573E0) >> 0h
1 (1185248225) (46A573E1) >> 0h
2 (1185248226) (46A573E2) >> 0h
3 (1185248227) (46A573E3) >> 0h
4 (1185248228) (46A573E4) >> 0h
5 (1185248229) (46A573E5) >> 0h
6 (1185248230) (46A573E6) >> 0h
7 (1185248231) (46A573E7) >> 0h
8 (1185248232) (46A573E8) >> 0h
9 (1185248233) (46A573E9) >> 0h
10 (1185248234) (46A573EA) >> 0h
11 (1185248235) (46A573EB) >> 0h
-------------------------------------------------------------------------------------
Hidden DWord for VT when FADF_HAVEVARTYPE = 0x0080
VT = 2 i.e. Integer
12 (1185248236) (46A573EC) >> 2h
13 (1185248237) (46A573ED) >> 0h
14 (1185248238) (46A573EE) >> 0h
15 (1185248239) (46A573EF) >> 0h
-------------------------------------------------------------------------------------
cDims = 1 i.e. One dimensional array
16 (1185248240) (46A573F0) >> 1h
17 (1185248241) (46A573F1) >> 0h
-------------------------------------------------------------------------------------
fFeatures = FADF_HAVEVARTYPE
18 (1185248242) (46A573F2) >> 80h
19 (1185248243) (46A573F3) >> 0h
-------------------------------------------------------------------------------------
cbElements = 2 i.e. element size is 2 bytes
20 (1185248244) (46A573F4) >> 2h
21 (1185248245) (46A573F5) >> 0h
22 (1185248246) (46A573F6) >> 0h
23 (1185248247) (46A573F7) >> 0h
-------------------------------------------------------------------------------------
cLocks
24 (1185248248) (46A573F8) >> 0h
25 (1185248249) (46A573F9) >> 0h
26 (1185248250) (46A573FA) >> 0h
27 (1185248251) (46A573FB) >> 0h
-------------------------------------------------------------------------------------
Padding
28 (1185248252) (46A573FC) >> 0h
29 (1185248253) (46A573FD) >> 0h
30 (1185248254) (46A573FE) >> 0h
31 (1185248255) (46A573FF) >> 0h
-------------------------------------------------------------------------------------
pvData
32 (1185248256) (46A57400) >> 0h
33 (1185248257) (46A57401) >> 97h
34 (1185248258) (46A57402) >> DCh
35 (1185248259) (46A57403) >> 1Bh
36 (1185248260) (46A57404) >> 0h
37 (1185248261) (46A57405) >> 0h
38 (1185248262) (46A57406) >> 0h
39 (1185248263) (46A57407) >> 0h
-------------------------------------------------------------------------------------
rgsabound(0).cElements = 10
40 (1185248264) (46A57408) >> Ah
41 (1185248265) (46A57409) >> 0h
42 (1185248266) (46A5740A) >> 0h
43 (1185248267) (46A5740B) >> 0h
-------------------------------------------------------------------------------------
rgsabound(0).lLbound
44 (1185248268) (46A5740C) >> 0h
45 (1185248269) (46A5740D) >> 0h
46 (1185248270) (46A5740E) >> 0h
47 (1185248271) (46A5740F) >> 0h
对于VBA 7的注释64位显示SAFEARRAYBOUNDS[0...]
在12月+24日的偏移,十六进制+18,这是由于pvData
的8字节内存地址和填充。
我希望可以帮助进一步说明SafeArray
函数到底在执行什么功能,以及SafeArray
结构项的位置。如果有人手动操作SafeArray
结构,请小心所有填充并正确设置偏移量。
我还将尝试解决有关VT_I4(3)或VT_R4(4)的查询。
在VBA中肯定还有一些额外的事情,从使用SafeArrayDescriptorEx进行测试以创建未设置cbElement的初始化的空Integer Array(设置了先前的VT)以来,SafeArray.c函数正在执行的操作。奇怪的是,对于Integer Array,在没有将cbElements设置为2个字节的情况下,VBA整数数组仍然可以工作。现在,在创建SafeArrayDescriptor时,我会手动设置cbElements。
使用上述VBA示例创建时,已正确设置了cbElement。
在SafeArray.c函数中,它们没有返回SizeOf(VT_I4)或SizeOf(VT_R4),即C语言不支持,因此我认为在VBA中必须扩展SafeArray.c函数并适应其数据类型,涵盖在C中。
更多了解C的人也许可以更好地阐明或解释。
答案 3 :(得分:1)
varType = SafeArrayGetVarType(mySafeArray);
SAFEARRAY
具有一个功能成员,该成员有助于描述数组中的内容
2.2.30.10 SAFEARRAY (archive)
- fFeatures::必须设置为2.2.9节中指定的位标志的组合。
然后您咨询:
2.2.9 ADVFEATUREFLAGS Advanced Feature Flags (archive)
在SAFEARRAY(第2.2.30.10节)数据类型的字段fFeatures中使用以下值。
typedef enum tagADVFEATUREFLAGS { FADF_AUTO = 0x0001, FADF_STATIC = 0x0002, FADF_EMBEDDED = 0x0004, FADF_FIXEDSIZE = 0x0010, FADF_RECORD = 0x0020, FADF_HAVEIID = 0x0040, FADF_HAVEVARTYPE = 0x0080, FADF_BSTR = 0x0100, FADF_UNKNOWN = 0x0200, FADF_DISPATCH = 0x0400, FADF_VARIANT = 0x0800 } ADVFEATUREFLAGS;
因此,根据FADF,您可以提出相应的变体类型:
| Feature Flag | Corresponding Variant Type |
|------------------|-------------------------------------|
| FADF_UNKNOWN | VT_UNKNOWN |
| FADF_DISPATCH | VT_DISPATCH |
| FADF_VARIANT | VT_VARIANT |
| FADF_BSTR | VT_BSTR |
| FADF_HAVEVARTYPE | SafeArrayGetVarType(mySafeArray) |
事实证明,上述所有工作(将FADF_BSTR与VT_BSTR等匹配)都由辅助函数SafeArrayGetVarType (archive)包裹:
对于基于 IUnknown 的SAFEARRAY类型,
- 如果设置了
FADF_HAVEVARTYPE
,则 SafeArrayGetVartype 返回存储在数组描述符中的VARTYPE。- 如果设置了
FADF_RECORD
,则返回VT_RECORD
;- 如果设置了
FADF_DISPATCH
,则返回VT_DISPATCH
;- 如果设置了
FADF_UNKNOWN
,则返回VT_UNKNOWN
。SafeArrayGetVartype 可能无法返回
VT_UNKNOWN
。呼叫者还应该检查SAFEARRAY类型的 fFeatures 字段是否设置了FADF_UNKNOWN
标志。