3

我想了解 SAFEARRAY 的实施。

在我看来,SAFEARRAY 结构中没有用于存储元素类型信息的字段,例如 VT_I4(3) 或 VT_R4(4),但 SafeArrayGetVartype 函数返回正确的类型。

有人在下面的MSDN页面上评论说,高位字cLocks持有类型信息:MSDN上的SAFEARRAY结构

但是当我通过类型库将 Long 和 Single 数组从 VBA 传递给 DLL 函数时,这些数组的 fFeatures 都是 0x80,cLocks 都是 0,并且 stll SafeArrayGetVartype 可以告诉 VT_I4(3) 和 VT_R4(4)。

4

4 回答 4

5

根据安全数组的创建方式,变体类型可能会在SAFEARRAY结构之前(从开始的偏移量 -4 处)存储在内存中。FADF_HAVEVARTYPEflag infFeatures表示该类型是否可用。

同样,FADF_HAVEIID表示 GUID(参见 参考资料SafeArrayCreateEx)存储在偏移量 -16 处,可通过SafeArrayGetIID. FADF_HAVEVARTYPE并且FADF_HAVEIID永远不能同时存在(因为否则VARTYPEGUID会在内存中重叠),但SafeArrayGetVartype足够聪明,可以在看到相应的特征标志时合成 或 类型VT_RECORD之一VT_DISPATCHVT_UNKNOWN

于 2013-09-13T12:55:10.007 回答
2

您永远不会手动初始化SAFEARRAY,它始终是调用的产物SafeArrayCreate,它为此结构分配内存。我认为假设为 SafeArray 的内部数据结构分配了一些额外的字节是安全的。那是可以存储任何扩展类型信息的地方。

于 2013-09-13T12:54:22.560 回答
2

要进一步扩展var 类型的存储位置并探索函数和其他函数SAFEARRAY到底在做什么,请参见:SafeArrayGetVartypeSafeArray

SafeArrayGetVartype

/* 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)

SafeArray 结构的内存转储,包括使用 MS Access VBA 7 的先前隐藏的 VT 数据

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 

由于 8 字节内存地址和填充 ,VBA 7 64 位的注释显示了SAFEARRAYBOUNDS[0...]+24 Dec,+18 hex的偏移量。pvData

我希望这有助于进一步解释任何SafeArray功能正在执行什么以及SafeArray结构项的位置。如果有人手动操作SafeArray结构,请注意任何填充并正确设置偏移量。

我还将尝试解决您关于 VT_I4(3) 或 VT_R4(4) 的问题。

在 VBA 中肯定有一些额外的事情发生,然后是 SafeArray.c 函数所执行的操作,因为从使用 SafeArrayDescriptorEx 创建一个初始化的空整数数组的测试开始,没有设置 cbElements,设置了前面的 VT。奇怪的是,VBA 整数数组仍然可以在没有将整数数组的 cbElements 设置为 2 个字节的情况下工作。创建 SafeArrayDescriptor 时,我现在手动设置 cbElements。

使用上述 VBA 示例创建时,cbElements 已正确设置。

在 SafeArray.c 函数中,它们不返回 SizeOf(VT_I4) 或 SizeOf(VT_R4),即 C 不支持,所以我假设在 VBA 中必须扩展 SafeArray.c 函数并满足 C 中未涵盖的数据类型.

对 C 有更多了解的人可能能够更好地澄清或解释。

于 2019-08-30T15:16:04.473 回答
1

精简版

varType = SafeArrayGetVarType(mySafeArray);

长版

SAFEARRAY一个features成员,可以帮助描述数组中的内容

2.2.30.10 SAFEARRAY 存档

  • fFeatures:必须设置为第2.2.9节中指定的位标志的组合。

然后你咨询:

2.2.9 ADVFEATUREFLAGS 高级功能标志 存档

以下值用于 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_RECORD: SAFEARRAY 必须包含 UDT 的元素(参见第 2.2.28.1 节)
  • FADF_HAVEIID: SAFEARRAY 必须包含 MInterfacePointers 元素。
  • FADF_HAVEVARTYPE: 如果设置了该位标志,则 SAFEARRAY 的 cLocks 字段的高位字必须包含描述数组元素类型的 VARIANT 类型常量(参见第 2.2.7 和 2.2.30.10 节)。
  • FADF_BSTR: SAFEARRAY 必须包含一个 BSTR 元素数组(参见第 2.2.23 节)。
  • FADF_UNKNOWN: SAFEARRAY 必须包含指向 IUnknown 的指针数组。
  • FADF_DISPATCH: SAFEARRAY 必须包含指向 IDispatch 的指针数组(参见第 3.1.4 节)。
  • FADF_VARIANT: SAFEARRAY 必须包含一个 VARIANT 实例数组。

所以根据FADF,你可以想出一个对应的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 )完成:

  • 如果FADF_HAVEVARTYPE设置,SafeArrayGetVartype返回存储在数组描述符中的 VARTYPE。
  • 如果FADF_RECORD设置,则返回VT_RECORD
  • 如果FADF_DISPATCH设置,则返回VT_DISPATCH
  • 如果FADF_UNKNOWN已设置,则返回VT_UNKNOWN.

SafeArrayGetVartype可能无法返回VT_UNKNOWN基于IUnknown的 SAFEARRAY 类型。调用者还应检查 SAFEARRAY 类型的fFeatures字段是否FADF_UNKNOWN设置了标志。

于 2018-10-05T17:57:34.847 回答