我有一个引用SharedPropertyGroupManager.CreatePropertyGroup的VB6项目,其中一个方法调用COMSVCSLib的VB6,将、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;为什么COMSVCSLib中的IDL/TypeLib枚举不作为枚举公开到VisualBasic6.0中?
发布于 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可能如下所示:
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可能像这样定义枚举:
typedef enum {
LockSetGet = 0,
LockMethod = 1
} LockModes;当midl编译器处理以这种方式编写的enum定义时,它会自动为enum生成一个名称(因为它丢失了--它应该出现在enum关键字之后)。这就是在OLE查看器中查看类型库时所看到的__MIDL名称。midl编译器还自动生成第二个typedef,它将typedef名称化成自动生成的enum名称。
问题是VB6无法理解以这种方式创建的枚举。它希望所有东西都在一个typedef中(即,您给enum一个名称,以及命名typedef):
typedef enum LocksMode {
LockSetGet = 0,
LockMethod = 1
} LocksMode;IDL对待typedef的方式与C或C++一样:您不必给枚举本身命名,因为typedef已经有了一个名称,但是如果您选择的话,可以给枚举一个名称。换句话说,typedef和enum实际上是两个独立的实体。VB6碰巧认识到typedef和enum是两个截然不同但又有模糊关联的东西,所以在您的例子中,它看到一个名为__MIDL___MIDL_itf_autosvcs_0469_0002的typedef,它看到这是一个未命名枚举的别名,它还看到了typedef for LockModes,这是另一个typedef的公共别名。
因为第一个typedef是公共的,所以您将在对象浏览器中看到LockModes的条目,而且因为它是枚举的别名,所以您也将在对象浏览器中看到枚举常量。然而,实际的枚举本身没有名称(因此它获得了浏览器中分配给它的时髦的自动生成的名称),而且VB6无法使用枚举,因为自动生成的名称在VB6中碰巧是非法的(带有双下划线的名称自动隐藏在VB6中)。
为了演示最后一点,如果您在VB6代码中键入这一点,Intellisense将工作并进行编译,但很明显,它并不是非常理想的:
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只为enum和typedef都提供了相同的名称(即typedef enum LockModes { ... } LockModes;),但是由于OLE查看器不一定生成有效的IDL,您可能需要对它进行更大的调整才能真正编译它。如果您可以让它正常工作,那么您可以从您的.tlb项目(而不是COMSVCSLib库)引用您的自定义COMSVCSLib,而enum的工作将按照您的预期进行。
如果您想走这条路线,还需要另外两个工具,它们应该已经安装在您的开发机器上(但是您可能需要搜索它们):
midl.exe:这个工具可以从一个.idl文件生成一个打字机文件(*.tlb)。因此,您可以将IDL从OLE查看器复制到记事本中,修改上面描述的枚举定义,将其保存为.idl文件,并将其传递给midl.exe以生成新的类型:
midl my-custom-typelib.idlregtlib.exe:这个工具可以注册一个.tlb文件,如果您想要将它添加为对VB6项目的引用,就需要这个文件:
regtlib.exe my-custom-typelib.tlb但是,为此创建一个自定义的类型可能是过度的,正如前面提到的,可能很难根据OLE查看器的输出获得可编译的IDL文件,因为它显示的是类型库的反向工程IDL,而不是原始的IDL。
发布于 2010-09-21 20:34:09
它是以明灯形式暴露的。在“类”列表中选择“LockModes”,然后查看较低的信息部分。你会发现这是个明灯。或者,您可以在代码中键入LockModes.,然后得到这两个选项。
在对象查看器中,枚举中的每个项都被标识为常量值,但它不是独立的const。当您在“类”列表中选择<globals>项时,独立控件将单独列出。
https://stackoverflow.com/questions/3764124
复制相似问题