为什么 TypeLib 枚举没有在 Visual Basic 6.0 中公开为枚举?
我有一个引用 COMSVCSLib 的 VB6 项目,其中一种方法调用 COMSVCSLib 的 SharedPropertyGroupManager.CreatePropertyGroup,并将 LockMethod 和 Process 作为参数传递。
清理了 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;
< 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.
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 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
它作为枚举公开。在类列表中选择 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.免责声明:我不是 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
创建公共名称LockModes
作为为enum
指定的自动生成的MIDL___MIDL_itf_autosvcs_0469_0002
名称。编译原始类型库时,midl
编译器为原始enum
生成长__MIDL
名称,并自动创建一个typedef< /code> 指向它的别名。
最初的 IDL 可能是这样定义枚举的:
当
midl
编译器处理以这种方式编写的enum
定义时,它会自动为enum
生成一个名称。 code> (因为它丢失了 - 它应该出现在enum
关键字之后)。这就是您在 OLE 查看器中查看类型库时看到的__MIDL
名称。midl
编译器还会自动生成第二个typedef
,它将typedef
名称别名为自动生成的enum
名称。问题是 VB6 无法理解以这种方式创建的枚举。它期望所有内容都在一个
typedef
中(即,您为enum
命名,并命名typedef
):IDL 处理 < code>typedef 与 C 或 C++ 的方式相同:您不必为枚举本身指定名称,因为
typedef
已经有一个名称,但是您可以如果您选择的话,可以给枚举命名。换句话说,typedef
和enum
实际上是两个独立的实体。 VB6 碰巧将typedef
和enum
识别为两个不同但模糊相关的事物,因此在您的情况下,它会看到一个名为的typedef
__MIDL___MIDL_itf_autosvcs_0469_0002
,它发现这是一个未命名枚举的别名,它还看到了LockModes
的typedef
,这是一个公共别名对于另一个typedef
。由于第一个
typedef
是公共的,因此您将在对象浏览器中看到LockModes
的条目,并且由于它是枚举的别名,因此您将在以及对象浏览器。但是,实际枚举本身没有名称(因此它会在浏览器中获取分配给它的时髦的自动生成名称),并且 VB6 无法使用枚举,因为自动生成的名称恰好在VB6中是非法的(带有双下划线的名称在VB6中会自动隐藏)。为了证明最后一点,如果您在 VB6 代码中键入此代码,Intellisense 将工作并且将编译,但显然,它不是很理想:
此代码工作的原因是因为您可以输入通常会导致语法错误的名称(例如以下划线开头的名称)放在括号中,以允许 VB6 接受通常非法的名称。此外,在常量前面加上自动生成的名称前缀可以与 Intellisense 配合使用,因为它是 VB6 与
enum
关联的实际名称(记住另一个typedef
只是一个别名)回到这个“真实的”,但自动生成的名称,VB6 显然无法将所有部分放在一起以实现两个名称引用相同的枚举
)。您还可以通过在枚举常量前加上库名称前缀来访问枚举常量,而不是像上面那样输入冗长的名称,例如,
COMSVCSLib.LockMethod
应该可以。我不太清楚为什么这实际上有效,并且我不确定如果两个不同的enum
定义具有相同名称的常量会发生什么。最后,您可以通过使用 OLE 查看器中的 IDL 创建自定义 IDL 文件以不同的方式解决此问题,在该文件中将现有的
enum
typedef 替换为单个typedef
对于每个简单地为enum
和typedef
提供相同名称的enum
(即typedef enum LockModes { ... } LockModes;
),但由于 OLE 查看器不一定生成有效的 IDL,因此您可能需要对其进行更多调整才能使其实际编译。如果您可以使其正常工作,那么您可以从 VB6 项目(而不是COMSVCSLib
库)引用自定义.tlb
和enum
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 sametypedef
where the enum constants are defined.When you view the type library in OLE Viewer, the
enum
probably looks like this:The first
typedef
creates the public nameLockModes
as an alias for the auto-generatedMIDL___MIDL_itf_autosvcs_0469_0002
name that was given to theenum
. When the original type libary was compiled, themidl
compiler generated the long__MIDL
name for the originalenum
and automatically created atypedef
alias pointing back to it.The original IDL probably defined the enum like this:
When the
midl
compiler processes anenum
definition written this way, it auto-generates a name for theenum
(since it is missing - it should appear after theenum
keyword). This is what the__MIDL
name is that you see when you view the type library in OLE Viewer. Themidl
compiler also automatically generates a secondtypedef
that aliases thetypedef
name to the auto-generatedenum
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 theenum
a name, as well as naming thetypedef
):IDL treats
typedef
's the same way that C or C++ does: you don't have to give the enum itself a name, because thetypedef
already has a name, but you can give the enum a name if you choose. In other words, thetypedef
and theenum
are actually two separate entities. VB6 happens to recognize thetypedef
and theenum
as being two distinct, but vaguely-related things, so in your case it sees atypedef
named__MIDL___MIDL_itf_autosvcs_0469_0002
, and it sees that this is an alias to an unnamed enum, and it also sees atypedef
forLockModes
, which is a public alias for the othertypedef
.Since the first
typedef
is public, you will see an entry forLockModes
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:
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 othertypedef
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 sameenum
).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 differentenum
'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 singletypedef
for eachenum
that simply gives both theenum
and thetypedef
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 theCOMSVCSLib
library), and theenum
'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 tomidl.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.