首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >为什么在VisualBasic6.0中TypeLib枚举不作为枚举公开?

为什么在VisualBasic6.0中TypeLib枚举不作为枚举公开?
EN

Stack Overflow用户
提问于 2010-09-21 20:17:51
回答 2查看 2.5K关注 0票数 6

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

清理了VB6代码:

代码语言:javascript
复制
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对象查看器中的定义来看,它们似乎被定义为枚举的值:

代码语言:javascript
复制
typedef enum {
    LockSetGet = 0,
    LockMethod = 1
} __MIDL___MIDL_itf_autosvcs_0469_0002;

为什么COMSVCSLib中的IDL/TypeLib枚举不作为枚举公开到VisualBasic6.0中?

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2010-09-21 23:54:34

免责声明:我不是IDL (接口定义语言,用于定义COM类型的语言)或Microsoft编译器(MIDL)方面的专家,但我在浏览了scrrun.dll的类型库之后得出了以下结论,该库与枚举存在类似的问题。这些信息有些是从关于IDL和VB6的DevX文章中收集到的:

VB6期望实际枚举有一个名称,而不仅仅是名称的typedefd。__MIDL___MIDL_itf_autosvcs_0469_0002名称是占位符,因为原始类型表没有在定义枚举常量的同一个typedef中定义枚举名。

当您在OLE查看器中查看类型库时,enum可能如下所示:

代码语言:javascript
复制
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名称的别名。当编译原始类型libary时,midl编译器为原始enum生成长__MIDL名称,并自动创建指向它的typedef别名。

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

代码语言:javascript
复制
typedef enum {
     LockSetGet = 0,
     LockMethod = 1
} LockModes;

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

问题是VB6无法理解以这种方式创建的枚举。它希望所有东西都在一个typedef中(即,您给enum一个名称,以及命名typedef):

代码语言:javascript
复制
typedef enum LocksMode {
    LockSetGet = 0,
    LockMethod = 1
} LocksMode;

IDL对待typedef的方式与C或C++一样:您不必给枚举本身命名,因为typedef已经有了一个名称,但是如果您选择的话,可以给枚举一个名称。换句话说,typedefenum实际上是两个独立的实体。VB6碰巧认识到typedefenum是两个截然不同但又有模糊关联的东西,所以在您的例子中,它看到一个名为__MIDL___MIDL_itf_autosvcs_0469_0002typedef,它看到这是一个未命名枚举的别名,它还看到了typedef for LockModes,这是另一个typedef的公共别名。

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

为了演示最后一点,如果您在VB6代码中键入这一点,Intellisense将工作并进行编译,但很明显,它并不是非常理想的:

代码语言:javascript
复制
MsgBox COMSVCSLib.[__MIDL___MIDL_itf_autosvcs_0469_0002].LockMethod

此代码之所以工作,是因为您可以将通常导致语法错误的名称(例如以下划线开头的名称)放在括号中,以允许VB6接受通常非法的名称。此外,用自动生成的名称作为常量的前缀适用于Intellisense,因为它是VB6与enum关联的实际名称(请记住,另一个typedef只是这个“真实”的别名,但是自动生成的名称,VB6显然不能将所有的部分放在一起来实现两个名称都指向同一个enum)。

您也可以通过在enum常量的前缀加上库名来访问COMSVCSLib.LockMethod常量,而不是像上面那样键入长得离谱的名称,例如,COMSVCSLib.LockMethod应该可以工作。我不太清楚这是为什么实际工作,我也不确定如果两个不同的enum定义相同名称的常量会发生什么。

最后,您可以通过使用OLE查看器中的IDL来创建一个自定义IDL文件,以不同的方式解决这个问题,在该文件中,您将现有的enum类型替换为每个enum的单个typedef,这些enum只为enumtypedef都提供了相同的名称(即typedef enum LockModes { ... } LockModes;),但是由于OLE查看器不一定生成有效的IDL,您可能需要对它进行更大的调整才能真正编译它。如果您可以让它正常工作,那么您可以从您的.tlb项目(而不是COMSVCSLib库)引用您的自定义COMSVCSLib,而enum的工作将按照您的预期进行。

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

  • midl.exe:这个工具可以从一个.idl文件生成一个打字机文件(*.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。

票数 11
EN

Stack Overflow用户

发布于 2010-09-21 20:34:09

它是以明灯形式暴露的。在“类”列表中选择“LockModes”,然后查看较低的信息部分。你会发现这是个明灯。或者,您可以在代码中键入LockModes.,然后得到这两个选项。

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

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/3764124

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档