免责声明:我不是 IDL(接口定义语言,用于定义 COM 类型的语言)或 Microsoft IDL 编译器 (MIDL) 方面的专家,但我来了在玩弄了 scrrun.dll 的类型库之后得出以下结论,这与 enum 有类似的问题。其中一些信息是通过快速浏览这篇关于 IDL 和 VB6 的 DevX 文章收集的:IDL for VB Tutorial
VB6 期望实际的枚举有一个名称,而不仅仅是一个名称为typedef'd 的枚举。 __MIDL___MIDL_itf_autosvcs_0469_0002 名称是一个占位符,因为原始类型库没有在定义枚举常量的同一 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 创建公共名称 LockModes 作为自动生成的 MIDL___MIDL_itf_autosvcs_0469_0002 名称的别名,该名称已分配给 enum。编译原始类型库时,midl 编译器为原始 enum 生成了长 __MIDL 名称,并自动创建了一个指向它的 typedef 别名。
原来的 IDL 大概是这样定义枚举的:
typedef enum {
LockSetGet = 0,
LockMethod = 1
} LockModes;
当midl 编译器处理以这种方式编写的enum 定义时,它会自动为enum 生成一个名称(因为它缺失 - 它应该出现在enum 关键字之后)。这就是您在 OLE 查看器中查看类型库时看到的 __MIDL 名称。 midl 编译器还会自动生成第二个 typedef,它将 typedef 名称别名为自动生成的 enum 名称。
问题在于 VB6 无法理解以这种方式创建的枚举。它希望所有内容都在一个 typedef 中(即您给 enum 一个名称,以及命名 typedef):
typedef enum LocksMode {
LockSetGet = 0,
LockMethod = 1
} LocksMode;
IDL 对待 typedef 的方式与 C 或 C++ 相同:您不必为枚举本身命名,因为 typedef 已经有了名称,但您可以 em> 如果您选择,请给枚举命名。换句话说,typedef 和enum 实际上是两个独立的实体。 VB6 碰巧将typedef 和enum 识别为两个不同但相关性模糊的事物,因此在您的情况下,它看到一个名为__MIDL___MIDL_itf_autosvcs_0469_0002 的typedef,它认为这是一个未命名的别名枚举,它还看到LockModes 的typedef,这是另一个typedef 的公共别名。
由于第一个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 定义具有相同名称的常量会发生什么。
最后,您可以通过使用 OLE 查看器中的 IDL 创建自定义 IDL 文件以不同的方式解决此问题,在该文件中,您将现有的 enum typedefs 替换为单个 typedef 用于每个 enum只需给enum 和typedef 赋予相同的名称(即typedef enum LockModes { ... } LockModes;),但由于OLE 查看器不一定生成有效的IDL,您可能需要对其进行更多调整才能使其实际编译.如果您可以让它工作,那么您可以从您的 VB6 项目(而不是 COMSVCSLib 库)中引用您的自定义 .tlb,并且 enum 将像您期望的那样工作。
如果你想走这条路,你还需要另外两个工具,它们应该已经安装在你的开发机器上(但你可能需要搜索它们):
-
midl.exe:此工具可以从.idl 文件生成类型库文件 (*.tlb)。因此,您可以将 OLE 查看器中的 IDL 复制到记事本中,如上所述修改枚举定义,将其保存为 .idl 文件,并将其传递给 midl.exe 以创建新的类型库:
midl my-custom-typelib.idl
-
regtlib.exe:这个工具可以注册一个 .tlb 文件,如果你希望能够将它作为引用添加到你的 VB6 项目中,这是必需的:
regtlib.exe my-custom-typelib.tlb
但是,为此创建自定义类型库可能有点过头了,而且如前所述,可能很难根据 OLE 查看器的输出获得可编译的 IDL 文件,因为它显示类型库的反向工程 IDL ,而不是原来的 IDL。