SAFEARRAY var类型存储在哪里?

时间:2013-09-13 10:49:00

标签: com automation safearray

我想了解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)。

4 个答案:

答案 0 :(得分:4)

根据safearray的创建方式,变体类型可以存储在内存中(从SAFEARRAY结构开始的偏移-4处)。 FADF_HAVEVARTYPE中的fFeatures标志表示该类型是否可用。

同样,FADF_HAVEIID表示GUID(请参阅SafeArrayCreateEx)存储在-16的偏移量处,并可通过SafeArrayGetIID获得。 FADF_HAVEVARTYPEFADF_HAVEIID永远不会同时出现(因为VARTYPEGUID会在内存中重叠),但SafeArrayGetVartype足够智能合成一个当VT_RECORDVT_DISPATCHVT_UNKNOWN类型看到相应的功能标记时,它们会显示。

答案 1 :(得分:2)

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

答案 2 :(得分:2)

要进一步扩展SAFEARRAY var类型的存储位置,并探究SafeArrayGetVartype函数和其他SafeArray函数的作用,请参见:

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 

对于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_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,您可以提出相应的变体类型:

| 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包裹:

  
      
  • 如果设置了FADF_HAVEVARTYPE,则 SafeArrayGetVartype 返回存储在数组描述符中的VARTYPE。
  •   
  • 如果设置了FADF_RECORD,则返回VT_RECORD
  •   
  • 如果设置了FADF_DISPATCH,则返回VT_DISPATCH
  •   
  • 如果设置了FADF_UNKNOWN,则返回VT_UNKNOWN
  •   
     对于基于 IUnknown 的SAFEARRAY类型,

SafeArrayGetVartype 可能无法返回VT_UNKNOWN。呼叫者还应该检查SAFEARRAY类型的 fFeatures 字段是否设置了FADF_UNKNOWN标志。