或与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的松散掌握 - 我可以创建简单的对象并实现简单的方法,但这超出了我的范围。
答案 0 :(得分:8)
收藏品或多或少基于惯例。他们实现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
答案 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
它提供了一个如何做到这一点的综合例子......