COM组件:可连接对象的VC实现

我们之前使用的COM组件都是由客户端发起请求,而COM组件提供服务,这样的通信都是单向的,但是有时我们需要双向的通信,比如当一个已经提供服务的COM组件对象触发某个保留的事件时,在前一段时间我们并不知道该怎么做,而现在明确了,但是COM组件已经提供服务,我们对于该事件的处理只能在客户端实现,这时候可连接对象就有了它用武之地了。现在我们说说可连接对象是怎么实现的吧

第一步建立ATL项目,暂时命名为link_obj吧,然后添加ATL简单对象,sobj,这里需要注意的是,要支持连接点,

:想到会自动生成一个_IsobjEvents事件接口,当然还有相应的DIID___IsobjEvents,这个接口就是出接口也就是说,该接口是要我们在客户端实现的接口,为该接口添

加测试成员函数HRESULT Msg,为了添加该成员函数,我们需要将idl以及link_obj_i.h文件中的接口定义都要进行改变,也就是说接口的定义涉及到着两个文件,在idl

中添加

importlib("stdole2.tlb");
	[
		uuid(9DB001A9-2F50-42A5-BE06-6EC2A8111A58)		
	]
	dispinterface _IsobjEvents
	{
		properties:
		methods:
			[id(1)] HRESULT Msg();
	};
	

我们只需要注意添加Msg这一行,

在link_obj_i.h文件中则添加

#if defined(__cplusplus) && !defined(CINTERFACE)

    MIDL_INTERFACE("9DB001A9-2F50-42A5-BE06-6EC2A8111A58")
    _IsobjEvents : public IDispatch
    {
		STDMETHOD(Msg)();
    };
    

为了测试,Msg函数要在Advise即连接时执行,那么我们要做的操作就是

STDMETHOD(Advise)(IUnknown *pUnkSink,
            /* [out] */ __RPC__out DWORD *pdwCookie)
	{
		_IsobjEvents*he=static_cast<_isobjevents>(pUnkSink);
		he->Msg();
		return S_OK;

	}
	
	
 
 

这样启动生成即可,就得到了.dll文件,现在我们要实现的就是客户端的程序了。

#include<iostream>
using namespace std;
#include"D:\project\link_obj\link_obj\link_obj_i.c"
#include"D:\project\link_obj\link_obj\link_obj_i.h"


class CSkin : public _IsobjEvents
{
public:
	CSkin(void){}
	~CSkin(void){}
private:
	DWORD m_dwRefCount;
public:
	HRESULT STDMETHODCALLTYPE QueryInterface(REFIID iid, void **ppvObject)
	{
		if (iid == DIID__IsobjEvents)
		{
			m_dwRefCount++;
			*ppvObject = (void *)this;
			return S_OK;
		}

		if (iid == IID_IUnknown)
		{
			m_dwRefCount++; 
			*ppvObject = (void *)this;
			return S_OK;
		}

		return E_NOINTERFACE;
	}
	ULONG STDMETHODCALLTYPE AddRef()
	{
		m_dwRefCount++;
		return m_dwRefCount;
	}
	

	ULONG STDMETHODCALLTYPE Release()
	{
		ULONG l;

		l = m_dwRefCount--;

		if ( 0 == m_dwRefCount)
		{
			delete this;
		}

		return l;
	}

	HRESULT STDMETHODCALLTYPE GetTypeInfoCount( 
		/* [out] */ __RPC__out UINT *pctinfo)
	{
		return S_OK;
	}

	HRESULT STDMETHODCALLTYPE GetTypeInfo( 
		/* [in] */ UINT iTInfo,
		/* [in] */ LCID lcid,
		/* [out] */ __RPC__deref_out_opt ITypeInfo **ppTInfo)
	{
		return S_OK;
	}
	STDMETHOD(Msg)()
	{
		::MessageBoxA(NULL,"正在执行Msg函数",0,0);
		return S_OK;
	}
	HRESULT STDMETHODCALLTYPE 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)
	{
		return S_OK;
	}

	/* [local] */ HRESULT STDMETHODCALLTYPE 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)
	{
		switch(dispIdMember) // 根据不同的dispIdMember,完成不同的回调函数,事件函数的ID编号
		{
		case 2:
			{
				// 1st param : [in] long lValue.

			}
			break;
		default: break;
		}

		return S_OK;
	}
};

int _tmain(int argc, _TCHAR* argv[])
{
	::CoInitialize(NULL);
	//创建COM对象实例
	IClassFactory*pcf=NULL;
	HRESULT hr=::CoGetClassObject(CLSID_sobj,CLSCTX_ALL,NULL,IID_IClassFactory,(void**)&pcf);
	Isobj* obj=NULL;
	hr=pcf->CreateInstance(NULL,IID_Isobj,(void**)&obj);
	pcf->Release();
	IConnectionPointContainer*ICPC=NULL;
	hr=obj->QueryInterface(IID_IConnectionPointContainer,(void**)&ICPC);
	IConnectionPoint*ICP=NULL;
	hr=ICPC->FindConnectionPoint(DIID__IsobjEvents,&ICP);
	CSkin *psk=new CSkin();
	IUnknown* pUk=NULL;
	hr=psk->QueryInterface(IID_IUnknown,(void**)&pUk);
	DWORD dw;
	ICP->Advise(pUk,&dw);
	ICP->Unadvise(dw);
	::CoUninitialize();
	return 0;
}

连接过程可以自己写,也可以使用系统默认的链接函数,均可

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

世纪殇

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值