如何使用ATL创建VB6集合对象

时间:2009-11-13 16:54:43

标签: c++ vb6 atl compatibility

或与VB6兼容 - 集合对象。

我们通过一组API为我们的.net产品提供钩子。

我们需要继续支持从VB6调用API的客户,因此我们需要继续支持VB6集合对象(在.net中使用VBA.Collection很简单)。

问题是支持一些使用VBScript调用我们API的网站。 VBScript没有集合对象的概念,因此要创建一个集合对象以传递给我们的API,我们构建了一个VB6 ActiveX DLL,它提供了一个“CreateCollection”方法。此方法只是创建并传回一个新的集合对象。问题解决了。

经过多年的修剪,移植和重建,这个DLL是我们唯一的VB6代码。因此,我们仍然需要在我们的开发和安装上安装Visual Studio 6。建造机器。

我对我们对这个DLL的依赖感到不满意有几个原因(我个人不喜欢VB6不是其中之一)。最重要的是微软不再支持Visual Studio 6。

我的问题是,如何让ATL创建一个实现与VB6集合对象相同接口的集合对象。

我对C ++有一个很好的处理,但只是对ATL的松散掌握 - 我可以创建简单的对象并实现简单的方法,但这超出了我的范围。

3 个答案:

答案 0 :(得分:8)

收藏品或多或少基于惯例。他们实现IDispatch并公开一些标准方法和属性:

  • Add() - 可选
  • Remove() - 可选
  • Item()
  • Count - 只读
  • _NewEnum - 隐藏只读,返回指向实现IEnumVariant的枚举器对象的指针

_NewEnum属性允许Visual Basic For Each

在IDL中,您使用dual界面并且:

    {li> 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

答案 1 :(得分:2)

让我们定位此VBScript代码段

Dim vElem
For Each vElem In MyObject
    ...
Next

特别是MyObject的实现。至少你必须在默认的dispinterface上实现一个DISPID_NEWENUM方法/ propget(它的双/ dispinterface来讨论DISPID)。你可以随心所欲地命名,没关系。大多数集合使用NewEnum,并在IDL中将其标记为隐藏。 VB6使用下划线前缀来标记隐藏的方法,因此您可能会看到_NewEnum作为推荐,但它是ATL的货物崇拜。

需要任何Count,Item,Add,Remove,Clear或任何其他方法(在默认界面上)。您可以提供这些作为方便(特别是项目访问者和可能是计数),但您不必,使上面的示例代码工作。

接下来,retval 作为一个单独的对象(所谓的枚举器),它通过使用指向MyObject的(私有)指针来实现IEnumVARIANT接口。在IDL中你可以声明retval,因为IUnknown在这里没有错。最有趣的是你 只能在IEnumVARIANT上实现Next方法,如果你愿意,可以在其余部分返回E_NOTIMPLEMENTED,或者可选择实现它们,尽管For Each永远不会调用它们。使实现更容易的是,下一个(请求的项目数)的celt参数总是 1,因此For Each请求项始终是一个接一个。

在ATL中可以使用的是CComEnumOnSTL等在STL容器上创建“代理”枚举器,或者基于数组的枚举器ATL提供(并排除STL)。

答案 2 :(得分:0)

有关如何实现在脚本编程语言中自然使用的COM集合的一个很好的示例,请查看my website

它提供了一个如何做到这一点的综合例子......