不幸的是,vbComponent Properties 集合的值/对象只是 CoClass 实例值的反映,因此它们在所有 VBA 主机上并不可靠。例如,你不能know认为Parent
属性将存在于 Properties 集合中。
当主机支持文档类型组件时,由主机定义文档支持的接口的 GUID。主机通常还负责创建/删除实际文档,就像只有 Excel 对象模型可以将工作表添加到工作簿中一样,而 VBIDE 则不能。
您已经谈到了工作簿和工作表,所以我将两者都包括在内......
不幸的是,VBIDE隐藏了一些关于文档类型组件的细节,它在导出模块时故意省略了这些细节,甚至将导出的文档类型模块转换为类模块文本,像这样Worksheet
called Sheet1
,这样它can't作为文档类型模块重新导入:
VERSION 1.0 CLASS
BEGIN
MultiUse = -1 'True
END
Attribute VB_Name = "Sheet1"
Attribute VB_GlobalNameSpace = False
Attribute VB_Creatable = False
Attribute VB_PredeclaredId = True
Attribute VB_Exposed = True
Sub Foo()
End Sub
将上面的内容与实际存储(以压缩格式)的文档模块文本进行比较Sheet1
module:
Attribute VB_Name = "Sheet1"
Attribute VB_Base = "0{00020820-0000-0000-C000-000000000046}"
Attribute VB_GlobalNameSpace = False
Attribute VB_Creatable = False
Attribute VB_PredeclaredId = True
Attribute VB_Exposed = True
Attribute VB_TemplateDerived = False
Attribute VB_Customizable = True
Sub Foo()
End Sub
注意 中存在的 3 个附加属性real模块文本:
Attribute VB_Base = "0{00020820-0000-0000-C000-000000000046}"
Attribute VB_TemplateDerived = False
Attribute VB_Customizable = True
GUID 0{00020820-0000-0000-C000-000000000046} 与CoClass Worksheet
,根据 OleViewer:
[
uuid(00020820-0000-0000-C000-000000000046),
helpcontext(0x0002a410)
]
coclass Worksheet {
[default] interface _Worksheet;
[default, source] dispinterface DocEvents;
};
工作簿模块也会发生相同的行为。这是 VBIDE 导出的文本:
VERSION 1.0 CLASS
BEGIN
MultiUse = -1 'True
END
Attribute VB_Name = "ThisWorkbook"
Attribute VB_GlobalNameSpace = False
Attribute VB_Creatable = False
Attribute VB_PredeclaredId = True
Attribute VB_Exposed = True
以及 VBA 二进制文件中 IStream 的原始文本:
Attribute VB_Name = "ThisWorkbook"
Attribute VB_Base = "0{00020819-0000-0000-C000-000000000046}"
Attribute VB_GlobalNameSpace = False
Attribute VB_Creatable = False
Attribute VB_PredeclaredId = True
Attribute VB_Exposed = True
Attribute VB_TemplateDerived = False
Attribute VB_Customizable = True
这次,正如预期的那样,GUID0{00020819-0000-0000-C000-000000000046}
是一个工作簿 CoClass:
[
uuid(00020819-0000-0000-C000-000000000046),
helpcontext(0x000305b8)
]
coclass Workbook {
[default] interface _Workbook;
[default, source] dispinterface WorkbookEvents;
};
以上内容都很值得了解,但它并不能解决您的问题,除非您可以获得组件的内存中 IStream 的句柄,但我认为您无法做到这一点。如果您可以从上次保存的主机文档版本中加载详细信息,那么您可以从基础文档中加载详细信息,但我认为您不希望这样做,and它最终可能是特定于主机的(考虑 Access 在表中存储 VBA 的方式。)
然而,VBIDEdoes为您提供有关 CoClass 的线索。 vbComponent 的属性集合返回exactCoClass 中存在的属性数量,如果您检查这些属性的名称、参数和类型,您会发现它们exactly匹配相应 CoClass 的成员,一直到它们在 CoClass 定义中出现的顺序。
例如,Worksheet vbComponent 的前 10 个属性是:
Application
Creator
Parent
CodeName
_CodeName
Index
Name
Next
OnDoubleClick
OnSheetActivate
以及对应的propget
(and propput
) 来自 CoClass Worksheet 中的 dispinterface _Worksheet 的条目(已删除方法):
[id(0x00000094), propget, helpcontext(0x0002a411)]
Application* Application();
[id(0x00000095), propget, helpcontext(0x0002a412)]
XlCreator Creator();
[id(0x00000096), propget, helpcontext(0x0002a413)]
IDispatch* Parent();
[id(0x0000055d), propget, helpcontext(0x0002a7fc)]
BSTR CodeName();
[id(0x80010000), propget, helpcontext(0x0002a7fd)]
BSTR _CodeName();
[id(0x80010000), propput, helpcontext(0x0002a7fd)]
void _CodeName([in] BSTR rhs);
[id(0x000001e6), propget, helpcontext(0x0002a7fe)]
long Index();
[id(0x0000006e), propget, helpcontext(0x0002a800)]
BSTR Name();
[id(0x0000006e), propput, helpcontext(0x0002a800)]
void Name([in] BSTR rhs);
[id(0x000001f6), propget, helpcontext(0x0002a801)]
IDispatch* Next();
[id(0x00000274), propget, hidden, helpcontext(0x0002a802)]
BSTR OnDoubleClick();
[id(0x00000274), propput, hidden, helpcontext(0x0002a802)]
void OnDoubleClick([in] BSTR rhs);
[id(0x00000407), propget, hidden, helpcontext(0x0002a803)]
BSTR OnSheetActivate();
如果您可以反映主机类型库的 CoClass 并散列属性names(也许只使用 propget 名称),然后您可以将哈希值与 VBIDE 的 component.Properties 集合中的名称的哈希值进行比较。
这是获取类型的迂回方式,但无法访问 IStream,我think这将是你唯一的方法。