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