Alf*_*ers 6 vb6 enums constants typelib
我有一个引用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
Run Code Online (Sandbox Code Playgroud)
几年没有使用VB6,起初我认为LockMethod和Process是在项目中的其他地方定义的变量或常量.
在对对象浏览器进行了一些研究后,我发现它们都在COMSVCSLib中作为常量公开.

但是在OLE/COM对象查看器中查看它们的定义,它们似乎被定义为枚举的值:
typedef enum {
LockSetGet = 0,
LockMethod = 1
} __MIDL___MIDL_itf_autosvcs_0469_0002;
Run Code Online (Sandbox Code Playgroud)
为什么COMSVCSLib中的IDL/TypeLib枚举不作为枚举公开给Visual Basic 6.0?
Mik*_*oss 11
免责声明:我不是IDL(接口定义语言,用于定义COM类型的语言)或Microsoft IDL编译器(MIDL)的专家,但是我在使用scrrun的类型库后得出了以下结论.dll,与enum有类似的问题.从这篇关于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;
Run Code Online (Sandbox Code Playgroud)
第一个typedef创建公共名称LockModes作为自动生成的MIDL___MIDL_itf_autosvcs_0469_0002名称的别名enum.编译原始类型库时,midl编译器为原始类型生成长__MIDL名称,enum并自动创建typedef指向它的别名.
原始IDL可能定义了这样的枚举:
typedef enum {
LockSetGet = 0,
LockMethod = 1
} LockModes;
Run Code Online (Sandbox Code Playgroud)
当midl编译器处理以enum这种方式编写的定义时,它会自动生成一个名称enum(因为它丢失了 - 它应该出现在enum关键字之后).这是__MIDL您在OLE Viewer中查看类型库时看到的名称.该midl编译器还自动生成一个第二typedef即别名typedef的名字到自动生成的enum名称.
问题是VB6无法理解以这种方式创建的枚举.它希望一切都在一个单独的typedef(即你给出enum一个名字,以及命名typedef):
typedef enum LocksMode {
LockSetGet = 0,
LockMethod = 1
} LocksMode;
Run Code Online (Sandbox Code Playgroud)
IDL typedef与C或C++的处理方式相同:您不必为枚举本身指定名称,因为typedef已经有了名称,但如果您选择,可以给枚举命名.换句话说,typedef和enum实际上是两个独立的实体.VB6恰好认识到typedef和enum两个截然不同但含糊不清的东西,所以在你的情况下它看到了一个typedef名字__MIDL___MIDL_itf_autosvcs_0469_0002,它看到这是一个未命名的枚举的别名,它也看到一个typedeffor LockModes,这是一个另一个的公共别名typedef.
由于第一个typedef是公共的,您将LockModes在对象浏览器中看到一个条目,并且因为它是枚举的别名,您还将在对象浏览器中看到枚举常量.但是,实际的枚举本身没有名称(因此它获得了在浏览器中分配给它的时髦自动生成的名称),并且VB6无法使用枚举,因为自动生成的名称在VB6中恰好是非法的(带有双下划线的名称会自动隐藏在VB6中.
为了证明最后一点,如果你在你的VB6代码中键入它,Intellisense将会工作并且它将被编译,但显然,它不是很理想:
MsgBox COMSVCSLib.[__MIDL___MIDL_itf_autosvcs_0469_0002].LockMethod
Run Code Online (Sandbox Code Playgroud)
此代码工作的原因是因为您可以将通常导致语法错误的名称(例如以下划线开头的名称)放在括号中,以允许VB6接受通常非法的名称.另外,使用自动生成的名称为常量添加前缀与Intellisense一起工作,因为它是VB6与之关联的实际名称enum(记住另一个typedef只是一个别名回到这个"真实",但是自动生成的名称,而VB6显然不能把所有的碎片放在一起,以实现两个名称相同enum).
您可以enum通过在库名称前加上常量来访问常量,而不是像上面那样输入可笑的长名称COMSVCSLib.LockMethod.我不太清楚为什么这实际上有效,而且我不确定如果两个不同enum的定义具有相同名称的常量会发生什么.
最后,您可以通过使用IDL从OLE查看器来创建自定义的IDL文件,在其中您替换现有的解决这个问题的不同方式enum与单一类型定义typedef为每个enum简单地给出了两个enum和typedef相同的名称(即typedef enum LockModes { ... } LockModes;) ,但由于OLE Viewer不一定生成有效的IDL,您可能不得不进行更多调整以使其实际编译.如果你可以让它工作,那么你可以.tlb从你的VB6项目(而不是COMSVCSLib库)中引用你的自定义,并且enum它将像你期望的那样工作.
如果你想走这条路,你需要的其他两个工具,应该已经安装在开发机器上了(但你可能需要搜索它们):
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 Viewer的输出可能很难获得可编译的IDL文件,因为它显示了类型库的反向工程IDL,而不是原始IDL.