我有一个引用 COMSVCSLib 的 VB6 项目,其中一种方法调用 COMSVCSLib 的 SharedPropertyGroupManager.CreatePropertyGroup 传递 锁定方法 和 进程作为参数。
清理 VB6 代码:
Dim groupName As String
Dim spmMgr As COMSVCSLib.SharedPropertyGroupManager
Dim spmGroup As COMSVCSLib.SharedPropertyGroup
Dim bGroupExists As Boolean
Set spmMgr = New COMSVCSLib.SharedPropertyGroupManager
With spmMgr
Set spmGroup = .CreatePropertyGroup(groupName, LockMethod, Process, bGroupExists)
End With
几年来没有使用 VB6,起初我认为 LockMethod 和 Process 是在项目中其他地方定义的变量或常量。
在对对象浏览器进行了一些研究后,我发现它们都在 COMSVCSLib 中作为常量公开。
但是在 OLE/COM 对象查看器中查看它们的定义,它们似乎被定义为枚举值:
typedef enum {
LockSetGet = 0,
LockMethod = 1
} __MIDL___MIDL_itf_autosvcs_0469_0002;
为什么来自 COMSVCSLib 的 IDL/TypeLib 枚举不作为枚举公开给 Visual Basic 6.0?
最佳答案
免责声明 :我不是 IDL(接口(interface)定义语言,它是用于定义 COM 类型的语言)或 Microsoft IDL 编译器 (MIDL) 的专家,但在玩弄 scrrun 的类型库后,我得出了以下结论。 dll,它与枚举有类似的问题。从快速浏览这篇关于 IDL 和 VB6 的 DevX 文章中收集到的一些信息:IDL for VB Tutorial
VB6 期望实际的枚举具有名称,而不仅仅是 typedef
的枚举。想要一个名字。 __MIDL___MIDL_itf_autosvcs_0469_0002
name 是一个占位符,因为原始类型库没有在同一个 typedef
中定义枚举名称。其中定义了枚举常量。
当您在 OLE 查看器中查看类型库时,enum
大概是这样的:
typedef [public] __MIDL___MIDL_itf_autosvcs_0469_0002 LockModes;
typedef enum {
LockSetGet = 0,
LockMethod = 1
} __MIDL___MIDL_itf_autosvcs_0469_0002;
第一
typedef
创建公共(public)名称 LockModes
作为自动生成 MIDL___MIDL_itf_autosvcs_0469_0002
的别名enum
的名称.编译原始类型库时,midl
编译器生成了长 __MIDL
原名enum
并自动创建了一个 typedef
别名指向它。最初的 IDL 可能像这样定义了枚举:
typedef enum {
LockSetGet = 0,
LockMethod = 1
} LockModes;
当
midl
编译器处理 enum
以这种方式编写的定义,它会自动为 enum
生成一个名称。 (因为它丢失了 - 它应该出现在 enum
关键字之后)。这是什么__MIDL
name 是您在 OLE 查看器中查看类型库时看到的名称。 midl
编译器还会自动生成第二个 typedef
别名 typedef
自动生成的名称 enum
姓名。问题是 VB6 无法理解以这种方式创建的枚举。它希望所有内容都集中在一个
typedef
中(即你给 enum
一个名字,以及命名 typedef
):typedef enum LocksMode {
LockSetGet = 0,
LockMethod = 1
} LocksMode;
IDL 款待
typedef
与 C 或 C++ 的方式相同:您不必为枚举本身命名,因为 typedef
已经有一个名字,但如果你愿意,你可以给枚举一个名字。换句话说,typedef
和 enum
实际上是两个独立的实体。 VB6 恰好能识别 typedef
和 enum
因为是两个不同但关联模糊的事物,所以在您的情况下,它会看到 typedef
命名 __MIDL___MIDL_itf_autosvcs_0469_0002
,它看到这是一个未命名枚举的别名,它也看到了 typedef
为 LockModes
,这是另一个 typedef
的公共(public)别名.自第一期
typedef
是公开的,您将看到 LockModes
的条目在对象浏览器中,并且因为它是枚举的别名,您还将在对象浏览器中看到枚举常量。但是,实际的枚举本身没有名称(因此它会在浏览器中获得分配给它的时髦的自动生成的名称),并且 VB6 无法使用该枚举,因为自动生成的名称在 VB6 中恰好是非法的(带有双下划线的名称在 VB6 中自动隐藏)。为了证明最后一点,如果你在你的 VB6 代码中输入这个,Intellisense 将工作并且它会编译,但显然,它不是很理想:
MsgBox COMSVCSLib.[__MIDL___MIDL_itf_autosvcs_0469_0002].LockMethod
这段代码有效的原因是因为您可以将通常会导致语法错误的名称(例如以下划线开头的名称)放在方括号中,以允许 VB6 接受通常非法的名称。此外,使用自动生成的名称作为常量前缀适用于 Intellisense,因为它是 VB6 与
enum
关联的实际名称。 (记住另一个 typedef
只是这个“真实”的别名,但自动生成的名称,VB6 显然不能把所有的部分放在一起来实现这两个名称指的是同一个 enum
)。除了像上面那样输入长得可笑的名字,您还可以访问
enum
以库名作为前缀来定义常量,例如,COMSVCSLib.LockMethod
应该管用。我不太清楚为什么这实际上有效,而且我不确定如果两个不同的 enum
会发生什么情况's 定义具有相同名称的常量。最后,您可以通过使用 OLE 查看器中的 IDL 创建自定义 IDL 文件以不同的方式解决此问题,您可以在其中替换现有的
enum
。带有单个 typedef
的 typedef每个enum
这只是给出了 enum
和 typedef
相同的名称(即 typedef enum LockModes { ... } LockModes;
),但由于 OLE 查看器不一定生成有效的 IDL,因此您可能需要对其进行更多调整才能使其实际编译。如果你可以让它工作,那么你可以引用你的自定义 .tlb
来自您的 VB6 项目(而不是 COMSVCSLib
库)和 enum
's 将像您期望的那样工作。如果你想走这条路,你需要另外两个工具,它们应该已经安装在你的开发机器上(但你可能需要搜索它们):
midl.exe
: 这个工具可以从 .idl
生成一个 typelib 文件 (*.tlb)文件。因此,您可以将 IDL 从 OLE 查看器复制到记事本中,如上所述修改枚举定义,将其保存为 .idl
文件,并将其传递给 midl.exe
制作一个新的类型库:midl my-custom-typelib.idl
regtlib.exe
:此工具可以注册一个 .tlb 文件,如果您希望能够将其添加为对 VB6 项目的引用,则需要该文件:regtlib.exe my-custom-typelib.tlb
但是,为此创建自定义类型库可能有点过头了,并且如前所述,可能很难根据 OLE 查看器的输出获得可编译的 IDL 文件,因为它显示的是类型库的逆向工程 IDL,而不是原始IDL。
关于vb6 - 为什么 TypeLib 枚举不在 Visual Basic 6.0 中公开为枚举?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3764124/