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

发布于 2024-09-24 12:54:15 字数 1018 浏览 4 评论 0原文

我有一个引用 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 中作为常量公开。

Object Browser

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

typedef enum {
    LockSetGet = 0,
    LockMethod = 1
} __MIDL___MIDL_itf_autosvcs_0469_0002;

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

I have a VB6 project that references COMSVCSLib and one of the methods makes calls to COMSVCSLib's SharedPropertyGroupManager.CreatePropertyGroup passing LockMethod and Process as parameters.

Cleaned up VB6 code:

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

Having not worked with VB6 for several years now, at first I thought LockMethod and Process were variables or constants defined somewhere else within the project.

After a little research on the Object Browser I found out that they were both being exposed as constants in COMSVCSLib.

Object Browser

But looking at their definition in OLE/COM Object Viewer, they seem to be defined as values of an enumeration:

typedef enum {
    LockSetGet = 0,
    LockMethod = 1
} __MIDL___MIDL_itf_autosvcs_0469_0002;

Why aren't IDL/TypeLib enums from COMSVCSLib being exposed as enums to Visual Basic 6.0?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

心如狂蝶 2024-10-01 12:54:16

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

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

It is exposed as an enum. Select LockModes in the classes list and take a look at the lower information section. You'll see that it is an enum. Or you could type LockModes. in your code and you would get the two options.

In the object viewer, each item within an enum is identified as a constant value but it is not a standalone const. Standalone consts are listed separately when you select the <globals> item in the classes list.

活雷疯 2024-10-01 12:54:15

免责声明我不是 IDL(接口定义语言,用于定义 COM 类型的语言)或 Microsoft IDL 编译器 (MIDL) 方面的专家,但我得出了结论在尝试了 scrrun.dll 的类型库后,如下所示,它与枚举有类似的问题。其中一些信息是通过快速查看有关 IDL 和 VB6 的 DevX 文章中收集到的:IDL for VB教程

VB6期望实际的枚举有一个名称,而不仅仅是一个通过typedef命名的枚举。 __MIDL___MIDL_itf_autosvcs_0469_0002 名称是一个占位符,因为原始 typelib 没有在定义枚举常量的同一 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 作为为 enum 指定的自动生成的 MIDL___MIDL_itf_autosvcs_0469_0002 名称。编译原始类型库时,midl编译器为原始enum生成长__MIDL名称,并自动创建一个typedef< /code> 指向它的别名。

最初的 IDL 可能是这样定义枚举的:

typedef enum {
     LockSetGet = 0,
     LockMethod = 1
} LockModes;

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

问题是 VB6 无法理解以这种方式创建的枚举。它期望所有内容都在一个 typedef 中(即,您为 enum 命名,并命名 typedef):

typedef enum LocksMode {
    LockSetGet = 0,
    LockMethod = 1
} LocksMode;

IDL 处理 < code>typedef 与 C 或 C++ 的方式相同:您不必为枚举本身指定名称,因为 typedef 已经有一个名称,但是您可以如果您选择的话,可以给枚举命名。换句话说,typedefenum 实际上是两个独立的实体。 VB6 碰巧将 typedefenum 识别为两个不同但模糊相关的事物,因此在您的情况下,它会看到一个名为的 typedef __MIDL___MIDL_itf_autosvcs_0469_0002,它发现这是一个未命名枚举的别名,它还看到了 LockModestypedef,这是一个公共别名对于另一个typedef

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

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

MsgBox COMSVCSLib.[__MIDL___MIDL_itf_autosvcs_0469_0002].LockMethod

此代码工作的原因是因为您可以输入通常会导致语法错误的名称(例如以下划线开头的名称)放在括号中,以允许 VB6 接受通常非法的名称。此外,在常量前面加上自动生成的名称前缀可以与 Intellisense 配合使用,因为它是 VB6 与 enum 关联的实际名称(记住另一个 typedef 只是一个别名)回到这个“真实的”,但自动生成的名称,VB6 显然无法将所有部分放在一起以实现两个名称引用相同的枚举)。

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

最后,您可以通过使用 OLE 查看器中的 IDL 创建自定义 IDL 文件以不同的方式解决此问题,在该文件中将现有的 enum typedef 替换为单个 typedef 对于每个简单地为 enumtypedef 提供相同名称的 enum (即 typedef enum LockModes { ... } LockModes;),但由于 OLE 查看器不一定生成有效的 IDL,因此您可能需要对其进行更多调整才能使其实际编译。如果您可以使其正常工作,那么您可以从 VB6 项目(而不是 COMSVCSLib 库)引用自定义 .tlbenum code> 将像您期望的那样工作。

如果您想走这条路,您还需要另外两个工具,它们应该已经安装在您的开发计算机上(但您可能需要搜索它们):

  • 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。

Disclaimer: I'm not an expert on IDL (Interface Definition Language, which is the language used to define COM types) or the Microsoft IDL compiler (MIDL), but I came to the conclusions below after playing around with the type library for scrrun.dll, which has a similar problem with enum's. Some of this information was gleaned from a quick look at this DevX article on IDL and VB6: IDL for VB Tutorial

VB6 expects the actual enum to have a name, not just a enum that is typedef'd to a name. The __MIDL___MIDL_itf_autosvcs_0469_0002 name is a placeholder, since the original typelib didn't define the enum name in the same typedef where the enum constants are defined.

When you view the type library in OLE Viewer, the enum probably looks like this:

typedef [public] __MIDL___MIDL_itf_autosvcs_0469_0002 LockModes;

typedef enum {
    LockSetGet = 0,
    LockMethod = 1
} __MIDL___MIDL_itf_autosvcs_0469_0002;

The first typedef creates the public name LockModes as an alias for the auto-generated MIDL___MIDL_itf_autosvcs_0469_0002 name that was given to the enum. When the original type libary was compiled, the midl compiler generated the long __MIDL name for the original enum and automatically created a typedef alias pointing back to it.

The original IDL probably defined the enum like this:

typedef enum {
     LockSetGet = 0,
     LockMethod = 1
} LockModes;

When the midl compiler processes an enum definition written this way, it auto-generates a name for the enum (since it is missing - it should appear after the enum keyword). This is what the __MIDL name is that you see when you view the type library in OLE Viewer. The midl compiler also automatically generates a second typedef that aliases the typedef name to the auto-generated enum name.

The problem is that VB6 can't understand enum's that are created this way. It expects everything to be in a single typedef (i.e. you give the enum a name, as well as naming the typedef):

typedef enum LocksMode {
    LockSetGet = 0,
    LockMethod = 1
} LocksMode;

IDL treats typedef's the same way that C or C++ does: you don't have to give the enum itself a name, because the typedef already has a name, but you can give the enum a name if you choose. In other words, the typedef and the enum are actually two separate entities. VB6 happens to recognize the typedef and the enum as being two distinct, but vaguely-related things, so in your case it sees a typedef named __MIDL___MIDL_itf_autosvcs_0469_0002, and it sees that this is an alias to an unnamed enum, and it also sees a typedef for LockModes, which is a public alias for the other typedef.

Since the first typedef is public, you will see an entry for LockModes in the Object Browser, and because it is an alias for an enum, you will see the enum constants in the Object Browser as well. However, the actual enum itself does not have a name (so it gets the funky auto-generated name assigned to it in the browser), and VB6 can't use the enum because the auto-generated name happens to be illegal in VB6 (names with double-underscores are automatically hidden in VB6).

To demonstrate that last point, if you type this in your VB6 code, Intellisense will work and it will compile, but obviously, it's not very ideal:

MsgBox COMSVCSLib.[__MIDL___MIDL_itf_autosvcs_0469_0002].LockMethod

The reason this code works is because you can put names that normally cause syntax errors (such as names that start with underscores) in brackets to allow VB6 to accept the normally-illegal name. In addition, prefixing the constants with the auto-generated name works with Intellisense because it is the actual name that VB6 associates with the enum (remember the other typedef is just an alias back to this "real", but auto-generated name, and VB6 apparently can't put all the pieces together to realize both names refer to the same enum).

Rather than typing out the ridiculously-long name like above, you can also access enum constants by prefixing them with the library name, for example, COMSVCSLib.LockMethod should work. It's less clear to me why this actually works, and I'm not sure what would happen if two different enum's define constants with the same name.

Lastly, you could fix this problem a different way by using the IDL from the OLE Viewer to create a custom IDL file, in which you replace the existing enum typedefs with a single typedef for each enum that simply gives both the enum and the typedef the same name (i.e. typedef enum LockModes { ... } LockModes;), but since the OLE Viewer doesn't necessarily generate valid IDL, you would probably have to tweak it even more to get it to actually compile. If you can get this to work, then you can reference your custom .tlb from your VB6 project (instead of the COMSVCSLib library), and the enum's will work like you would expect them to.

If you want to go that route, there are two other tools you need, which should already been installed on your development machine (but you may need to search for them):

  • midl.exe: This tool can generate a typelib file (*.tlb) from a .idl file. So you could copy the IDL from the OLE Viewer into Notepad, modify the enum definitions as described above, save it as a .idl file, and pass it to midl.exe to make a new typelib:

    midl my-custom-typelib.idl

  • regtlib.exe: This tool can register a .tlb file, which is required if you want to be able to add it as a reference to your VB6 project:

    regtlib.exe my-custom-typelib.tlb

However, creating a custom typelib for this is probably overkill, and as already mentioned, it might be hard to get a compilable IDL file based off the output from the OLE Viewer, since it displays reverse-engineered IDL for the type library, not the original IDL.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文