CComPtr和CComQIPtr

  这里两个对接口指针的封装类,也就是智能指针,使用只能指针有如下优势:

  1.析够函数自动释放接口指针
  2.处理异常时智能指针可以自动析够
  3.赋值操作可以自动处理释放、AddRef的资源管理
  4.构造函数、类型转换等自动处理了类似QI等若干问题

  CComQIPtr继承了CComPtr,使用CComPtr的地方都可以使用CComQIPtr,而且使用CComQIPtr的地方多数也可以使用CComPtr,需要注意的地方只是CComQIPtr的构造函数,如果类型参数是IUnknown,必须显式指定第二个参数,否则编译出错,这是我理解的区别了。

  下面的代码我展示了我能想到的这个智能指针的方方面面,注意代码只是为了展示功能,也就是可以编译通过,但是执行未必正确。(IDispath特化这段是可以提出来编译运行的,只是需要我自己写的一个com,所以还是没有运行意义的。)

	//代码说明:G.IDispatch特例化单拿出来出可以编译运行的(当然需要我自己写的com),其他运行会异常,只是展示用法,但求编译通过即可。
	CComPtr
  
  	punk;
	CComQIPtr
  
  	pdsp;
	//类型转换中,punk的QueryInterface会被调用
	pdsp	= punk;

	//CComPtr需要一个类型信息作为模板参数,而CComPtr额外需要一个IID指针作为模板参数,不过该参数为默认参数(&__uuidof
  
  )
	CComQIPtr
  
  				pdsp1;
	CComQIPtr	pdsp2;
	CComQIPtr	pdsp3;

	//A.构造函数
	CComPtr
  
  	ccpt1;		//构造一个NUL
	IDispatch*	myprDsp	= NULL;
	CComPtr
  
  	ccpt2(myprDsp);	//这里如果prUnk非NUL,则构造函数会调用一次prUnk->AddRef()
	//不同类型的接口指针,构造函数会内部调用QI方法
	CComQIPtr	ccpt3(ccpt2);	//当使用CComQIPtr类想让构造函数调用QI方法时,不加IID参数编译不过
	CComPtr
  
  	test(ccpt2);					//CComPtr没有这个问题

	//B.赋值	赋值操作三部曲:1.当当前指针不为NUL,释放,2.当源指针不为NUL,AddRef,3.用源指针替换当前指针
	ccpt3	= ccpt1;

	//C.实例化对象的方法
	CComPtr
  
  	ccpt4;
	ccpt4.CoCreateInstance(CLSID_MySharp);	//需要CLSID,如果使用聚合,还需要pUnkOuter,当然,一如com,你也可以再传一个参数dwClsContext

	//D.资源管理
	//1.资源释放
	ccpt3	= NULL;		//赋值NUL,释放资源
	ccpt1.Release();	//调用Release显式释放
	ccpt2	= NULL;
	ccpt4.Release();
	//2.指针赋值,拷贝出一个新的生命周期完全独立的指针
	IUnknown*	myprUnk;
	punk.CopyTo(&myprUnk);
	//3.类型转换,CComPtr的类型转换没有在目标类型指针上自动调用AddRef方法
	punk	= (IUnknown*)ccpt4;
	punk	= ccpt4;			//两种方式都能接受,内部都是调用了QI方法
	//4.转移控制权
	myprUnk	= punk.Detach();		//Detach
	punk.Attach(myprUnk);			//Attach
	
	//E.其他操作
	IDispatch*	myprDsp2;
	//1.简化的查询方法
	punk.QueryInterface(&myprDsp2);		
	//2.在两个IUnknow上查询是否是同一com对象,它会负责自动转换(自动调用QI)
	if (punk.IsEqualObject(ccpt4))
	{
	}
	//3.处理聚合
	punk.SetSite(myprUnk);
	//4.处理连接点关联
	DWORD	dwCookie;
	punk.Advise(myprDsp2,IID_IDispatch,&dwCookie);

	//F.比较操作,CComPtr可以用!检查NUL情况,其他operator<、operator==、operator!=都是为了适用STL而定义的
	if (!punk)
	{
	}
	
	//G.IDispath特化
	//1.访问属性示例
	CoInitialize(NULL);
	CComPtr
  
  	c17ptr;		//必须使用IDispach指针才可以使用这些特性(使用了模板的偏特化处理的,所以必须使用IDispach了)
	c17ptr.CoCreateInstance(CLSID_MySharp,NULL);
	CComVariant	comvar(3,VT_I4);
	//a.只通过属性名进行设置
	c17ptr.PutPropertyByName(OLESTR("xpos"),&comvar);		
	comvar.Clear();
	VARIANT	rvar;
	rvar.vt	=VT_EMPTY;
	//b.只通过属性名进行获取
	c17ptr.GetPropertyByName(OLESTR("xpos"),&rvar);			
	VariantClear(&rvar);
	//c.使用属性的DISPID
	DISPID	dispidXpos;			//其实DISPID就是IDL文件里定义的属性/方法id,因为oleidl.h里定义:typedef LONG DISPID;
	c17ptr.GetIDOfName(OLESTR("xpos"),&dispidXpos);
	VARIANT	rvar2;
	VariantInit(&rvar2);
	c17ptr.GetProperty(dispidXpos,&rvar2);
	//d.有两个静态方法,可以直接使用IDispach*(而不必是CComPtr封装的指针)来通过DISPID设置或获取参数
	IDispatch*	rdisp	= c17ptr.Detach();
	rvar2.vt	= VT_EMPTY;
	CComPtr
  
  ::GetProperty(rdisp,1,&rvar2);	//get
	CComPtr
  
  ::PutProperty(rdisp,2,&rvar2);	//put
	c17ptr.Attach(rdisp);
	//e.Invoke方法,er,真的,如果没有封装,直接使用invoke方法真的是梦魇
	CComPtr
  
  	c17calc;
	c17calc.CoCreateInstance(CLSID_MCalcServer);
	CComVariant	par1(7.0);
	CComVariant	par2(8.0);
	c17calc.Invoke2(OLESTR("doAdd"),&par2,&par1);		//使用两个参数的版本,这里要注意参数顺序是由右到左的
	rvar2.vt	= VT_EMPTY;
	c17calc.GetPropertyByName(OLESTR("addResult"),&rvar2);
	VariantClear(&rvar2);
	c17calc	= NULL;
	c17ptr	= NULL;
	CoUninitialize();
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值