为什么在Visual Basic 6.0中没有将TypeLib枚举公开为枚举?

Alf*_*ers 6 vb6 enums constants typelib

我有一个引用COMSVCSLib的VB6项目,其中一个方法调用COMSVCSLib的SharedPropertyGroupManager.CreatePropertyGroup传递LockMethodProcess作为参数.

清理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
Run Code Online (Sandbox Code Playgroud)

几年没有使用VB6,起初我认为LockMethod和Process是在项目中的其他地方定义的变量或常量.

在对对象浏览器进行了一些研究后,我发现它们都在COMSVCSLib中作为常量公开.

对象浏览器

但是在OLE/COM对象查看器中查看它们的定义,它们似乎被定义为枚举的值:

typedef enum {
    LockSetGet = 0,
    LockMethod = 1
} __MIDL___MIDL_itf_autosvcs_0469_0002;
Run Code Online (Sandbox Code Playgroud)

为什么COMSVCSLib中的IDL/TypeLib枚举不作为枚举公开给Visual Basic 6.0?

Mik*_*oss 11

免责声明:我不是IDL(接口定义语言,用于定义COM类型的语言)或Microsoft IDL编译器(MIDL)的专家,但是我在使用scrrun的类型库后得出了以下结论.dll,与enum有类似的问题.从这篇关于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;
Run Code Online (Sandbox Code Playgroud)

第一个typedef创建公共名称LockModes作为自动生成的MIDL___MIDL_itf_autosvcs_0469_0002名称的别名enum.编译原始类型库时,midl编译器为原始类型生成长__MIDL名称,enum并自动创建typedef指向它的别名.

原始IDL可能定义了这样的枚举:

typedef enum {
     LockSetGet = 0,
     LockMethod = 1
} LockModes;
Run Code Online (Sandbox Code Playgroud)

midl编译器处理以enum这种方式编写的定义时,它会自动生成一个名称enum(因为它丢失了 - 它应该出现在enum关键字之后).这是__MIDL您在OLE Viewer中查看类型库时看到的名称.该midl编译器还自动生成一个第二typedef即别名typedef的名字到自动生成的enum名称.

问题是VB6无法理解以这种方式创建的枚举.它希望一切都在一个单独的typedef(即你给出enum一个名字,以及命名typedef):

typedef enum LocksMode {
    LockSetGet = 0,
    LockMethod = 1
} LocksMode;
Run Code Online (Sandbox Code Playgroud)

IDL typedef与C或C++的处理方式相同:您不必为枚举本身指定名称,因为typedef已经有了名称,但如果您选择,可以给枚举命名.换句话说,typedefenum实际上是两个独立的实体.VB6恰好认识到typedefenum两个截然不同但含糊不清的东西,所以在你的情况下它看到了一个typedef名字__MIDL___MIDL_itf_autosvcs_0469_0002,它看到这是一个未命名的枚举的别名,它也看到一个typedeffor LockModes,这是一个另一个的公共别名typedef.

由于第一个typedef是公共的,您将LockModes在对象浏览器中看到一个条目,并且因为它是枚举的别名,您还将在对象浏览器中看到枚举常量.但是,实际的枚举本身没有名称(因此它获得了在浏览器中分配给它的时髦自动生成的名称),并且VB6无法使用枚举,因为自动生成的名称在VB6中恰好是非法的(带有双下划线的名称会自动隐藏在VB6中.

为了证明最后一点,如果你在你的VB6代码中键入它,Intellisense将会工作并且它将被编译,但显然,它不是很理想:

MsgBox COMSVCSLib.[__MIDL___MIDL_itf_autosvcs_0469_0002].LockMethod
Run Code Online (Sandbox Code Playgroud)

此代码工作的原因是因为您可以将通常导致语法错误的名称(例如以下划线开头的名称)放在括号中,以允许VB6接受通常非法的名称.另外,使用自动生成的名称为常量添加前缀与Intellisense一起工作,因为它是VB6与之关联的实际名称enum(记住另一个typedef只是一个别名回到这个"真实",但是自动生成的名称,而VB6显然不能把所有的碎片放在一起,以实现两个名称相同enum).

您可以enum通过在库名称前加上常量来访问常量,而不是像上面那样输入可笑的长名称COMSVCSLib.LockMethod.我不太清楚为什么这实际上有效,而且我不确定如果两个不同enum的定义具有相同名称的常量会发生什么.

最后,您可以通过使用IDL从OLE查看器来创建自定义的IDL文件,在其中您替换现有的解决这个问题的不同方式enum与单一类型定义typedef为每个enum简单地给出了两个enumtypedef相同的名称(即typedef enum LockModes { ... } LockModes;) ,但由于OLE Viewer不一定生成有效的IDL,您可能不得不进行更多调整以使其实际编译.如果你可以让它工作,那么你可以.tlb从你的VB6项目(而不是COMSVCSLib库)中引用你的自定义,并且enum它将像你期望的那样工作.

如果你想走这条路,你需要的其他两个工具,应该已经安装在开发机器上了(但你可能需要搜索它们):

  • 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 Viewer的输出可能很难获得可编译的IDL文件,因为它显示了类型库的反向工程IDL,而不是原始IDL.