您的位置:首页 > 其它

COM组件对象如何实现索引属性

2009-07-06 08:17 495 查看
在前面的系列文章中,我们知道了如何实现javascript和COM对象之间的互操作。在这里,我们再来看一个特殊的应用--索引属性。索引属性,就是让COM对象可以象一个数组一样的访问。比如,我们有一个COM对象实例oMyArray,在javascript中可以这样调用:

//标准方式
oMyArray.item(0)="test";
alert(oMyArray.item(0));

//缺省属性的方式
oMyArray(0)="test";
alert(oMyArray(0));

//索引属性的方式
oMyArray[0]="test";
alert(oMyArray[0]);


缺省属性很好实现,就是让COM对象提供一个DISPID=0的属性方法即可。

索引属性,就需要重载 IDispatch接口的GetIDsOfNames和Invoke方法。

我们先看看javascript是如何执行索引属性的。

javascript遇到oMyArray[0]时,调用IDispatch.GetIDsOfNames方法,查看是否存在名称为“0”的属性。如果存在,就用返回的DISPID继续调用IDispatch.Invoke方法。

为了方便起见,在下面的示例中,只支持long型的索引参数。

__interface IMyArray : IDispatch
{
[id(00000000), propget]
HRESULT Item([in] VARIANT VarKey,[out, retval] VARIANT* pvar);
[id(00000000), propput]
HRESULT Item([in] VARIANT VarKey,[in] VARIANT pvar);

class ATL_NO_VTABLE CMyArray :
public IDispatchImpl<IMyArray>
{

public:
HRESULT FinalConstruct()
{
m_nIndexCounter=10000;
}

private:
//方便起见,仅支持long型的索引名
CAtlMap<long,_variant_t> m_oMapFromNameToValue;

//支持索引式的访问
DISPID m_nIndexCounter;
CAtlMap<DISPID,long>	m_oMapFromIdToIndex;
CAtlMap<long,DISPID>	m_oMapFromIndexToId;

public:
//支持缺省属性
STDMETHOD(get_Item)(VARIANT VarKey,VARIANT* pvar);
STDMETHOD(put_Item)(VARIANT VarKey,VARIANT pvar);

//支持索引属性
STDMETHOD(GetIDsOfNames)(REFIID riid, LPOLESTR* rgszNames, UINT cNames,
LCID lcid, DISPID* rgdispid);
STDMETHOD(Invoke)(DISPID dispidMember, REFIID riid,
LCID lcid, WORD wFlags, DISPPARAMS* pdispparams, VARIANT* pvarResult,
EXCEPINFO* pexcepinfo, UINT* puArgErr);

};

///////实现

STDMETHODIMP CMyArray::get_Item(VARIANT VarKey,VARIANT* pvar)
{
//
_variant_t vResult;
m_oMapFromNameToValue.Lookup(VarKey.lVal,vResult);

*pvar=vResult.Detach();
return S_OK;
}

STDMETHODIMP CMyArray::put_Item(VARIANT VarKey,VARIANT pvar)
{
//
m_oMapFromNameToValue.SetAt(VarKey.lVal,pvar);
return S_OK;
}

STDMETHODIMP CMyArray::GetIDsOfNames(REFIID riid, LPOLESTR* rgszNames, UINT cNames,
LCID lcid, DISPID* rgdispid)
{
//
HRESULT hr=__super::GetIDsOfNames(riid, rgszNames, cNames, lcid, rgdispid);
if(hr!=DISP_E_UNKNOWNNAME)
return hr;

//作为索引属性来使用
long nIndex=_wtol(rgszNames[0]);

DISPID nDispId;
if(this->m_oMapFromIndexToId.Lookup(nIndex,nDispId))
{
*rgdispid=nDispId;
}
else
{
nDispId=++m_nIndexCounter;

this->m_oMapFromIdToIndex.SetAt(nDispId,nIndex);
this->m_oMapFromIndexToId.SetAt(nIndex,nDispId);

*rgdispid=nDispId;
}

//
return S_OK;
}

STDMETHODIMP CMyArray::Invoke(DISPID dispidMember, REFIID riid,
LCID lcid, WORD wFlags, DISPPARAMS* pdispparams, VARIANT* pvarResult,
EXCEPINFO* pexcepinfo, UINT* puArgErr)
{
//可以先判断是否为索引属性,因为索引属性是从10000开始的,不会冲突
long nIndex;
if(this->m_oMapFromIdToIndex.Lookup(dispidMember,nIndex))
{
if(wFlags & DISPATCH_PROPERTYGET)
{
return this->get_Item(_variant_t(nIndex),pvarResult);
}
else if( ( (wFlags & DISPATCH_PROPERTYPUT) || (wFlags & DISPATCH_PROPERTYPUTREF) )
&& pdispparams->cArgs==1
)
{
return this->put_Item(_variant_t(nIndex),pdispparams->rgvarg[0]);
}
else
{
return E_FAIL;
}
}
else
{
return __super::Invoke( dispidMember, riid, lcid,
wFlags, pdispparams, pvarResult, pexcepinfo, puArgErr);
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐