VB6 / VBA遍历所有预先声明的类对象

San*_*arn 2 vb6 excel vba ms-office

我可以动态遍历所有预声明的对象吗?

这是我已经解决了一段时间的问题。理想情况下,我将遍历所有类并检查它们是否实现了某些接口。如果确实如此,则对它们执行一些代码。

目前,我必须提供一些要执行的类数组:

ClassesToCheck = Array(Task_Class1,Task_Class2,Task_Class3,Task_Class4, ...)

Dim klass as object
For each klass in ClassesToCheck
  if klass.implements(ITask) then
    Call klass.execute()
  end if
next
Run Code Online (Sandbox Code Playgroud)

在理想的世界中,我会这样做:

Dim klass as object
For each klass in GET_PREDECLARED_CLASS_OBJECTS_FROM_MEMORY()
  if klass.implements(ITask) then
    Call klass.execute()
  end if
next
Run Code Online (Sandbox Code Playgroud)

我不希望有任何简单的方法来执行此操作,但是我已经对VBA运行时内存进行了一些研究/探索...我认为应该可以,并使用VBA6.DLL找到了一些VB6示例。但是,不幸的是,Microsoft Office本身没有提供此DLL。但是,VBA6.DLL可能被“编译为” Microsoft Office本身。所以方法/字段也应该保存在内存中的某个地方,您只需要知道它们在哪里使用指针数学即可(这是我的理论)

我不认为有人对此有任何经验吗?

Mat*_*don 5

一个VB_PredeclaredId属性,使您的Class1标识用这个名字自动指全球范围内的对象,例如,UserForm1是一类模块的名称(一个设计师,但是这部分是无关紧要的),并且它是通过催生了一个全球性的,AUTOMAGIC对象的名称VBA在运行时,并且编译器知道Class1.DoStuff合法,因为它知道Class1VB_PredeclaredId设置为True

感谢Wayne Phillips(vbWatchDog)和其他贡献者的工作和贡献,Rubberduck充分利用了此内部API

如链接代码(C#)所示,您可以通过将指针变成具有以下特定布局的结构,ITypeLib从其References集合中获取VBA项目的名称:

[StructLayout(LayoutKind.Sequential)]
internal struct VBEReferencesObj
{
    IntPtr _vTable1;     // _References vtable
    IntPtr _vTable2;
    IntPtr _vTable3;
    IntPtr _object1;
    IntPtr _object2;
    public IntPtr _typeLib; // <--- here's the pointer you want
    IntPtr _placeholder1;
    IntPtr _placeholder2;
    IntPtr _refCount;
}
Run Code Online (Sandbox Code Playgroud)

在VBA中,这是用户定义的Type,可能如下所示:

Public Type VBEReferencesObj
    vTable1 As LongPtr
    vTable2 As LongPtr
    vTable3 As LongPtr
    object1 As LongPtr
    object2 As LongPtr
    typelibPointer As LongPtr '<~ only this one matters
    placeholder1 As LongPtr
    placeholder2 As LongPtr
    refCount As LongPtr
End Type
Run Code Online (Sandbox Code Playgroud)

一旦有了指向的指针ITypeLib,您就应该能够获得VBA项目的类型库。

从那里开始,您将要遍历类型,并从那里确定类型是否TYPEFLAGSTYPEFLAG_PREDECLID打开(我们在此处进行操作)。

显然,这是很多极易发生崩溃的反复试验编码,我不建议您进行任何此类编码,但是在任何情况下,即使不建议这样做也是可能的

随时学习Rubberduck.VBEEditor.ComManagement.TypeLibs命名空间。