17.ATL实现IDispatch自动化接口

在一般情况下,简单的IDispatch接口我们可以不依赖类型库来完成,但是对于分发函数比较多或是需要具体类型信息的场合,还是需要使用类型库来实现IDispatch接口。


1.通用的依赖类型库实现IDispatch

前面讲了在ATL中使用类型库创建接口的方法,这里以ATL来演示通用的借助类型库实现IDispatch接口的过程。但是实际上只要提供类型库,在MFC中也可以使用此方法。

编辑类型库,声明一个接口继承自IDispatch

[
	object,
	uuid(CA00179E-7AD8-4C6D-8544-23A571C31D8C),
	dual,
	nonextensible,
	helpstring("ICat 接口"),
	pointer_default(unique)
]
interface ICat : IDispatch{
	[id(1)] HRESULT SayHello1([in] BSTR szWord);
	[id(2)] HRESULT SayHello2([in] int nAge);
};
注意这里声明为双端接口dual,在双端接口下既可通过Invoke调用方法也可以通过直接获取接口调用对应的方法,兼顾了脚本语言的易用性和编译语言的性能。


ATL使用多重继承实现COM,所以声明COM组件对象如下:

class ATL_NO_VTABLE CAnimalObject :
	public CComObjectRootEx<CComSingleThreadModel>,
	public CComCoClass<CAnimalObject, &CLSID_AnimalObject>,
	public ICat


这里声明一个类型信息接口指针ITypeInfo* m_pITI;,具体实现如下:

自定义函数加载类型库,导出对应的信息接口指针

HRESULT CAnimalObject::MyLoadTypeLib(LCID lcid, ITypeInfo **ppTInfo)
{
	HRESULT		hr=E_FAIL;
	ITypeLib	*pTypeLib=NULL;

	if (ppTInfo==NULL)
	{
		return E_POINTER;
	}
	*ppTInfo = NULL;

	if (m_pITI==NULL)
	{
		//加载Type Lib
		hr = LoadRegTypeLib(LIBID_AtlDispatchLib, 1, 0, lcid, &pTypeLib);
		if (FAILED(hr))
		{
			hr = LoadTypeLib(OLESTR("AtlDispatch.tlb"), &pTypeLib);
		}
		if (FAILED(hr))
		{
			return hr;
		}

		//导出TypeInfo接口
		hr = pTypeLib->GetTypeInfoOfGuid(IID_ICat, &m_pITI);
		pTypeLib->Release();
		if (FAILED(hr))
		{
			return hr;
		}
	}

	*ppTInfo = m_pITI;
	m_pITI->AddRef();
	OutputDebugString(L"类型库加载成功");
	return S_OK;
}

存在类型库,所以GetTypeInfoCount实现如下:

HRESULT STDMETHODCALLTYPE CAnimalObject::GetTypeInfoCount( 
	/* [out] */ __RPC__out UINT *pctinfo)
{
	*pctinfo = 1;	//存在类型库
	return S_OK;
}

GetTypeInfo、GetIDsOfNames、Invoke均借助于ITypeInfo接口,如下:

HRESULT STDMETHODCALLTYPE CAnimalObject::GetTypeInfo( 
	/* [in] */ UINT iTInfo,
	/* [in] */ LCID lcid,
	/* [out] */ __RPC__deref_out_opt ITypeInfo **ppTInfo)
{
	if (0!=iTInfo)//0表示获取该接口实现的类型信息
	{
		return TYPE_E_ELEMENTNOTFOUND;
	}

	return  MyLoadTypeLib(lcid, ppTInfo);
}

HRESULT STDMETHODCALLTYPE CAnimalObject::GetIDsOfNames( 
	/* [in] */ __RPC__in REFIID riid,
	/* [size_is][in] */ __RPC__in_ecount_full(cNames) LPOLESTR *rgszNames,
	/* [range][in] */ UINT cNames,
	/* [in] */ LCID lcid,
	/* [size_is][out] */ __RPC__out_ecount_full(cNames) DISPID *rgDispId)
{

	HRESULT hr = E_FAIL;
	ITypeInfo* pTypeInfo=NULL;

	if (riid!=IID_NULL)//riid为保留参数,必须为IID_NULL
	{
		return DISP_E_UNKNOWNINTERFACE;
	}

	//借用类型库完成GetIDsOfNames
	hr = GetTypeInfo(0, lcid, &pTypeInfo);
	if (SUCCEEDED(hr) && pTypeInfo)
	{
		hr = pTypeInfo->GetIDsOfNames(rgszNames, cNames, rgDispId);
		pTypeInfo->Release();
	}
	return hr;
}

HRESULT STDMETHODCALLTYPE CAnimalObject::Invoke( 
	/* [in] */ DISPID dispIdMember,
	/* [in] */ REFIID riid,
	/* [in] */ LCID lcid,
	/* [in] */ WORD wFlags,
	/* [out][in] */ DISPPARAMS *pDispParams,
	/* [out] */ VARIANT *pVarResult,
	/* [out] */ EXCEPINFO *pExcepInfo,
	/* [out] */ UINT *puArgErr)
{
	HRESULT hr = E_FAIL;
	ITypeInfo* pTypeInfo=NULL;

	if (riid!=IID_NULL)//riid为保留参数,必须为IID_NULL
	{
		return DISP_E_UNKNOWNINTERFACE;
	}

	hr = GetTypeInfo(0, lcid, &pTypeInfo);
	if (FAILED(hr) || NULL==pTypeInfo)
	{
		return hr;
	}

	//借用类型库完成Invoke
	hr = pTypeInfo->Invoke((ICat*)this, dispIdMember, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
	if (FAILED(hr))
	{
		pTypeInfo->Release();
		return DISP_E_EXCEPTION;
	}

	pTypeInfo->Release();
	return hr;
}

2.ATL中的实现IDispatch方法

ATL实现IDispatch接口非常简单,和上面的同样方法实现一样,只是IDispatch接口实现放在了类IDispatchImpl中,我们只要如下声明即完成了IDispatch接口。

class ATL_NO_VTABLE CAnimalObject :
	public CComObjectRootEx<CComSingleThreadModel>,
	public CComCoClass<CAnimalObject, &CLSID_AnimalObject>,
	public IDispatchImpl<ICat, &IID_ICat, &LIBID_AtlDispatchLib, /*wMajor =*/ 1, /*wMinor =*/ 0>
是不是非常简单?

实际上,IDispatchImpl做的事情和我们之前的方法一模一样,只是微软做了个封装而已,如果感兴趣可以自行阅读源码。


3.调用IDispatch接口

类似MFC中借助COleDispatchDriver类简化Invoke函数调用,ATL中借助CComDispatchDriver类来简化Invoke函数调用,如下:

	//初始化COM库
	if (CoInitialize(NULL) != S_OK)
	{
		wcout << L"Fail to Initialize COM" << endl;
		return -1;
	}

	//自动化调用
	CComDispatchDriver d;   

	if (SUCCEEDED(d.CoCreateInstance(CLSID_AnimalObject)))
	{
		CComVariant p1;  
		p1.vt = VT_BSTR;  
		p1.bstrVal = SysAllocString(L"毛毛");

		CComVariant p2;  
		p2.vt = VT_I4;  
		p2.lVal = 12;  

		d.Invoke1(1, &p1, NULL);
		d.Invoke1(2, &p2, NULL);

		d.Release();
	}	

	::CoUninitialize();


IDispatch ATL实现方法下载链接

原创,转载请注明来自http://blog.csdn.net/wenzhou1219

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值