COM Collection接口定义类似于:
[ object, dual ] template <typename T> interface ICollection : IDispatch { [propget] HRESULT Count([out, retval] long* pnCount); [id(DISPID_VALUE), propget] HRESULT Item([in] long n, [out, retval] T* pnItem); [id(DISPID_NEWENUM), propget] HRESULT _NewEnum([out, retval] IUnknown** ppEnum); };
由于没有办法确定集合中包含的何种元素,上述是假想定义,假想IDL支持template,值得注意的是这个接口要支持IDispatch
COM Enum接口定义类似于:
template <typename T> interface IEnum : IUnknown { [local] HRESULT Next([in] ULONG celt, [out] T* rgelt, [out] ULONG *pceltFetched); [call_as(Next)] // Discussed later... HRESULT RemoteNext([in] ULONG celt, [out, size_is(celt), length_is(*pceltFetched)] T* rgelt, [out] ULONG *pceltFetched); HRESULT Skip([in] ULONG celt); HRESULT Reset(); HRESULT Clone([out] IEnum<T> **ppenum); }
同样是假想定义
实际中的ICollection定义为:
[dual]
interface IPrimeNumbers : IDispatch {
HRESULT CalcPrimes([in] long min, [in] long max);
[propget]
HRESULT Count([out, retval] long* pnCount);
[propget, id(DISPID_VALUE)]
HRESULT Item([in] long n, [out, retval] long* pnPrime);
[propget, id(DISPID_NEWENUM)] // Not quite right...
HRESULT _NewEnum([out, retval] IEnumPrimes** ppEnumPrimes);
};
而实际中IEnum定义为:
interface IEnumPrimes : IUnknown {
[local]
HRESULT Next([in] ULONG celt,
[out] long* rgelt,
[out] ULONG *pceltFetched);
[call_as(Next)]
HRESULT RemoteNext([in] ULONG celt,
[out, size_is(celt),
length_is(*pceltFetched)] long* rgelt,
[out] ULONG *pceltFetched);
HRESULT Skip([in] ULONG celt);
HRESULT Reset();
HRESULT Clone([out] IEnumPrimes **ppenum);
};
Dealing with the Enumerator local/call_as Oddity
Next有两种Local和Remote
Local允许pceltFetched为NULL
Remote不允许pceltFetched为NULL
对于Proxy过来的请求,需要在proxy-stub实现时加上一段代码,书上给出了使用cpp_quote在idl文件中添加这个例程的手段。
Enumeration and Visual Basic 6.0
如果IEnum要支持VB的for each指令,ICollection必须要继承IDispatch而且必须要有_NewEnum和作为DISPID的DISPID_NEWENUM,VB代码就是调用Invoke(DISPID_NEWENUM)来实现的。例如:
[dual] interface IPrimeNumbers : IDispatch { HRESULT CalcPrimes([in] long min, [in] long max); [propget] HRESULT Count([out, retval] long* pnCount); [propget, id(DISPID_VALUE)] HRESULT Item([in] long n, [out, retval] long* pnPrime); [propget, id(DISPID_NEWENUM)] HRESULT _NewEnum([out, retval] IUnknown** ppunkEnum); };
如果VB要支持Item,则必须要通过DISPID_VALUE
注意,虽然Next函数具有每次访问多个数据的能力,VB每次只访问一个数据