2020-10-19

CComPtr和CComQIPtr

CComPtr和CComQIPtr是智能接口指针类,它们在销毁的时候,不需要手动去释放接口指针,在赋值的时候,也不需要手动的AddRef,在出现异常的时候,会自动处理异常,而不需要额外的异常处理代码。

 

     CComPtr和CComQIPtr的不同的地方:CComPtr只能创建固定的特定的接口指针实例。而CComQIPtr不但实现了CComPtr的所有的功能,而且当我们把一个不同类型的接口指针赋值给CComQIPtr的时候,CComQIPtr会自动的调用接口指针的QueryInterface接口,来获得对应的正确的接口指针。

 

     (1) 构造函数

            第一个参数为智能接口指针的类型,第二个参数为 智能指针的接口ID。

 

            CComPtr<IUnknown> punk;

 

            //下面三个例子完全相同

            CComPtr<IXXX> pno;

            CComPtr<IXXX,&__uuidof(IXXX)> pno;

            CComPtr<IXXX,&IID_IXXX> pno;

 

      CComQIPtr可以用任何一个类型的接口指针初始化,如果初始化的值与CComQIPtr的类型相同,那么构造函数简单调用 指针的AddRef,但是,如果类型不同的话,它会先调用指针的QueryInterface来获得相同的类型的接口指针,当QueryInterface失败的话,内部指针会被设置为NULL。

           所有下面的代码,可以用来检测是否转换成功:

void  Func(IUnknown * punk)  
  
{  
  
      CComQIPtr<IXXX> pno(punk);  
  
      if(pno)  
  
     {  
  
        //正确转换  
  
        pno->doSomething();  
  
     }  
  
}  

2)赋值

          赋值的时候,发生下面三件事:

          111.  如果当前指针不为空,那么释放当前指针

          222.   如果源指针不为空,那么AddRef

          333.   将当前指针设置为源指针

     oprator =  可以让我们把任何一个CComPtr赋值给CComQIPtr对象,如果有必要就会调用QueryInterface .

          例如:

CComQIPtr<IFoo>   fooPtr;  
  
CComQIPtr<IBar>    barPtr;  
  
  
  
barPtr=fooPtr; 

    (3)  CoCreateInstance方法

         CComPtr提供了一个实例化对象的方法

 

          HRESULT   CoCreateInstance(REFCLSID  rclsid,LPUNKNOWN  pUnkOuter=NULL, DWORD dwClsCOntext=CLSCTX_ALL);

 

 

          HRESULT   CoCreateInstance(LPCOLESTR szProgID, LPUNKNOSWN

pUnkOuter=NULL, DWORD  dwClsContxt=CLSCTX_ALL);

 

         后两个参数不管,第一个参数要不传入CLSID,要不传入字符串形式的progID.

        

        例子代码如下:

CComPtr<IXXX> ptr;  
  
HRESULT  hr=ptr.CoCreateInstance(__uuidof(IXXX));  

(4)  operator *()

          当对CComPtr解除指针的引用时,跟普通的指针一样,返回一个内部指针类型的引用。

 

     (5)   operator &()

 

          获取智能指针对象的地址,实际上也是返回内部指针的地址,跟普通指针一样。

 

     (6)  在调用ComUninitialize方法前,需要手动释放所有的全局或者静态变量。

 

            如何手动释放呢:

            111.设置指针指向NULL

            222.调用Release方法,注意是要调用智能指针的Release方法,而不是内部指针的,指针指针的Release方法,会调用内部指针的Relase,然后设置内部指针为NULL,这样就可以防止多次释放接口。

 

     (7)CopyTo方法,拷贝后的智能指针生命周期完全独立。

 

            我们用CopyTo方法,将指针拷贝到一个out型参数。

 

      (8)Detach 和Attach方法

 

           在返回一个我们不再需要的接口指针给调用者的时候,我们可以用Deatch方法。

 

            当我们需要把原始指针的所有权转移到智能指针时候,用Attach方法。

 

 

       (9)  QueryInterface方法

              他只需要传入期望获得的接口类型的变量地址,即可。

 

              CComPtr<IFoo>   pFoo=...;

 

              CComPtr<IBar>   pBar;

 

              HRESULT   hr= pFoo.QueryInterface(&pBar);

 

       (10)  IsEqualObject方法

               IsEqualObject方法用来判断两个接口指针释放引用的是同一个对象。

 

              

 

       (11)  !=  和 ==  操作符

 

               跟普通的 一样

 

       (12)  CComPtr对IDispatch的特化

 

               CComPtr<IDispatch>  iptr;

 

               属性调用的辅助函数

               111.  GetIDOfName(LPCOLESTR  lpsz,DISPID  * pdispid)

                        这个方法,获得属性的DISPID

 

                222.GetProPerty(DISPID  dwDispid,  VARIANT *  pVar)

                       这个方法,获得属性。

                       SetProPerty(DISPID  dwDispid,  VARIANT *  pVar)

                       这个方法,设置属性。

 

               333. GetPropertyByName(LPCOLESTR lpsz, VARIANT * pVar)

                       SetPropertyByName(LPCOLESTR lpsz, VARIANT * pVar)

                       直接通过名称,获得和设置属性。

 

 

                            

               方法调用的辅助函数:

               111. HRESULT  Invoke0(DISPID dispid,VARIANT * pvarRet=NULL);

                       通过DISPID调用 没有参数的方法。

 

                       HRESULT  Invoke0(LPCOLESTR  lpszName, VARIANT * pvarRet=NULL);

                       通过方法名称,调用没有参数的方法。

 

                       HRESULT  Invoke1(DISPID dispid,VARIANT * param1, VARIANT *

pvarRet=NULL);

                       通过DISPID调用 有一个参数的方法。

 

                       HRESULT  Invoke1(LPCLOESTR  lpszName ,VARIANT * param1,

VARIANT * pvarRet=NULL);

                       通过方法名称,调用有一个参数的方法。

 

 

                       HRESULT  InvokeN(DISPID dispid,VARIANT* params, int  nParams,   VARIANT * pvarRet=NULL);

                       通过DISPID调用有N个参数的方法。

 

                       HRESULT InvokeN(LPCLOESTR   lpszName ,VARIANT * params,int  nParams,  VARIANT * pvarRet=NULL);

                      通过方法名称调用有N个参数的方法。

 

                       注意,通过参数列表的方法调用的时候,参数是反向的顺序,最后一个参数是元素0。  切记。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值