如何使用 ATL 创建 VB6 集合对象
Posted
技术标签:
【中文标题】如何使用 ATL 创建 VB6 集合对象【英文标题】:How to create a VB6 collection object with ATL 【发布时间】:2010-12-16 09:00:34 【问题描述】:或一个 VB6 兼容的集合对象。
我们通过一组 API 为我们的 .net 产品提供挂钩。
我们需要继续支持从 VB6 调用我们 API 的客户,因此我们需要继续支持 VB6 集合对象(在 .net 中使用 VBA.Collection 很简单)。
问题在于支持一些使用 VBScript 调用我们的 API 的网站。 VBScript 没有集合对象的概念,因此为了创建一个集合对象以传递给我们的 API,我们构建了一个提供“CreateCollection”方法的 VB6 ActiveX DLL。此方法只是创建并传回一个新的集合对象。问题解决了。
经过多年的修剪、移植和重建,这个 DLL 是我们仅有的 VB6 代码。因此,我们仍然需要在我们的开发和构建机器上安装 Visual Studio 6。
我对我们对这个 DLL 的依赖不满意有几个原因(我个人不喜欢 VB6 不是其中之一)。最重要的是微软不再支持 Visual Studio 6。
我的问题是,如何让 ATL 创建一个实现与 VB6 集合对象相同接口的集合对象。
我对 C++ 有很好的了解,但对 ATL 的掌握很松散——我可以创建简单的对象并实现简单的方法,但这超出了我的能力范围。
【问题讨论】:
听起来这个 VB6 DLL 很少更改。你真的需要那么频繁地构建它吗?我的想法是不再支持VB6 IDE,但支持VB6 runtime。如果你不需要大量构建DLL,IDE不支持是不是一个大问题? 我知道你在说什么,但我们有法律义务能够构建我们所有的代码。我们不能拥有无法构建的非 3rd 方组件。 VB6 中的“强类型”集合仍然通过 IEnumVARIANT 枚举。强制转换是隐式完成的(并且可能会失败)。 【参考方案1】:集合或多或少基于惯例。它们实现了IDispatch
并公开了一些标准方法和属性:
Add()
- 可选
Remove()
- 可选
Item()
Count
- 只读
_NewEnum
- 隐藏,只读,返回指向实现IEnumVariant
的枚举器对象的指针
_NewEnum
属性允许 Visual Basic For Each
。
在 IDL 中,您使用 dual
接口并且:
DISPID_VALUE
为Item()
[propget, id(DISPID_NEWENUM), restricted] HRESULT _NewEnum([out, retval] IUnknown** pVal)
这里有一些 MSDN 条目:Design Considerations for ActiveX Objects 这里有一些 ATL 特定的便利:ATL Collections and Enumerators
【讨论】:
【参考方案2】:让我们以这个 VBScript sn-p 为目标
Dim vElem
For Each vElem In MyObject
...
Next
尤其是MyObject的实现。作为最低要求,您必须在默认分配接口上实现一个带有 DISPID_NEWENUM 的方法/propget(它的双/分配接口谈论 DISPID)。你可以给它起任何你想要的名字,没关系。大多数集合使用 NewEnum,并在 IDL 中将其标记为隐藏。 VB6 使用下划线前缀标记隐藏方法,因此您可能会将 _NewEnum 视为推荐,但它是一种货物崇拜 ATL。
您根本不需要任何计数、项目、添加、删除、清除或任何其他方法(在默认界面上)。您可以提供这些以方便使用(特别是 Item 访问器,可能还有 Count),但您不必这样做,以使上面的示例代码正常工作。
接下来,retval 必须是一个单独的对象(所谓的枚举器),它通过使用指向 MyObject 的(私有)指针来实现 IEnumVARIANT 接口。在 IDL 中,您可以在这里将 retval 声明为 IUnknown 没有任何问题。最有趣的是您必须仅在 IEnumVARIANT 上实现 Next 方法,如果您愿意,您可以在其余部分返回 E_NOTIMPLEMENTED,或者选择实现它们,尽管 For Each 从未调用这些方法。使实现更加简单的是 Next 的 celt 参数(请求的项目数)总是 1,因此 For Each 总是一个接一个地请求项目。
您可以在 ATL 中使用 CComEnumOnSTL 等在 STL 容器上创建“代理”枚举器,或者 ATL 提供的基于数组的枚举器(并排除 STL)。
【讨论】:
For Each 不需要 Count 等,但可能会破坏使用它们的其他代码。 MSDN 还说它必须命名为 _NewEnum - 虽然这对于 VB6 可能不是必需的,但它可能会破坏其他代码......msdn.microsoft.com/en-us/library/ms221672.aspx 我见过 CComEnumOnSTL 对象和 ATL 集合对象。这是一个“被宠坏了”的问题,我不知道该选择哪个。关于在 ATL 中构建集合对象的任何建议,我可以将其传递给需要 VB6 集合的 VB6 函数? @gf:Active Directory 对象是支持枚举而不暴露 Item/Count 的 coclass 的一个示例。在转到最后一个元素之前,我不确定他们是否知道计数。【参考方案3】:有关如何实现在脚本编程语言中自然使用的 COM 集合的一个很好的示例,请查看my website
它提供了一个全面的例子来说明如何做到这一点......
【讨论】:
以上是关于如何使用 ATL 创建 VB6 集合对象的主要内容,如果未能解决你的问题,请参考以下文章
创建 ATL COM 对象后如何填写 ProgID。 ProgID 重要性