6

我有一个引用 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

几年来没有使用 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?

4

2 回答 2

11

免责声明我不是 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为两个不同但相关性模糊的事物,因此在您的情况下,它会看到一个typedefnamed __MIDL___MIDL_itf_autosvcs_0469_0002,它会看到 this 是未命名枚举的别名,它还会看到typedeffor LockModes,这是另一个的公共别名typedef

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

为了证明最后一点,如果您在 VB6 代码中键入此内容,Intellisense 将工作并编译,但显然,它不是很理想:

MsgBox COMSVCSLib.[__MIDL___MIDL_itf_autosvcs_0469_0002].LockMethod

此代码有效的原因是您可以将通常会导致语法错误的名称(例如以下划线开头的名称)放在括号中,以允许 VB6 接受通常非法的名称。此外,使用自动生成的名称为常量添加前缀适用于 Intellisense,因为它是enumVB6typedef与不能将所有部分放在一起以实现两个名称指的是相同的enum)。

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

最后,您可以通过使用 OLE 查看器中的 IDL 创建自定义 IDL 文件以不同的方式解决此问题,在该文件中,您将现有的enumtypedefs 替换为一个单独typedef的 typedefs,每个enum只给出相同的名称enumtypedef相同的名称(即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。

于 2010-09-21T23:54:34.357 回答
1

它作为枚举公开。在类列表中选择 LockModes 并查看下方信息部分。你会看到它是一个枚举。或者你可以输入LockModes.你的代码,你会得到两个选项。

在对象查看器中,枚举中的每个项目都被标识为一个常量值,但它不是一个独立的常量。<globals>当您在类列表中选择项目时,独立的 const 将单独列出。

于 2010-09-21T20:34:09.610 回答