CComPtr(com智能指针)用法以及CImage加载图像流示例

 1. **COM接口指针很危险**

COM接口指针很危险,因为使用过程中需要每一个使用者都要严格并且正确的AddRef和Release,一旦出现问题,就会造成对象不能被正常释放,或者对象被重复删除,造成程序崩溃。所以使用COM接口,必须小心翼翼才行。
但是,即使所有的代码中,都正确的AddRef和Release,也不一定能保证万无一失,例如:

void SomeApp( IHello * pHello )
   {
        IHello* pCopy = pHello;
        pCopy->AddRef(); 
        OtherApp();
        pCopy->Hello();
        pCopy->Release();
    }


看起来好像无懈可击,但是假设OtherApp中抛出了异常,那么pCopy->Release不就被跳过去了吗?
幸好,所有的问题都从简单到复杂,再从复杂到简单的,因为我们有CComPtr!

 2.**智能指针**
 
CComPtr被称为智能指针,是ATL提供的一个模版类,能够从语法上自动完成AddRef和Release。(源代码在atlbase.h中)
CComPtr的用法很简单,以IHello*为例,将程序中所有接口指针类型(除了参数),都使用CComPtr<IHello> 代替即可。即程序中除了参数之外,再也不要使用IHello*,全部以CComPtr<IHello>代替。
CComPtr的用法和普通COM指针几乎一样,另外使用中有以下几点需要注意。
 1. CComPtr已经保证了AddRef和Release的正确调用,所以不需要,也不能够再调用AddRef和Release。
 2. 如果要释放一个智能指针,直接给它赋NULL值即可。(这一点要牢记曾因为没有设置为null而出错)
 3. CComPtr本身析构的时候会释放COM指针。
 4. 当对CComPtr使用&运算符(取指针地址)的时候,要确保CComPtr为NUL。(因为通过CComPtr的地址对CComPtr赋值时,不会自动调用AddRef,若不为NULL,则前面的指针不能释放,CComPtr会使用assert报警)
以刚才的程序为例:

​

void SomeApp( IHello * pHello )
{
    CComPtr<IHello> pCopy = pHello;
    OtherApp();
    pCopy->Hello();
}

​


由于pCopy是一个局部的对象,所以即使OtherApp()抛出异常,pCopy也会被析构,指针能够被释放。
如果不想在程序临近发布前,还因为COM指针的引用计数造成崩溃的话,就牢记这一点吧:程序中除了参数之外,不要直接使用COM指针类型,一定要全部以CComPtr<IXXX>代替。


 3. **示例**```

void OnDrawImage(CDC *pDC, unsigned char* pbyteImage, int size,CRect rect)
{
    CImage image;

    CComPtr<IStream> stream;
    stream = NULL;

    HGLOBAL hMem = ::GlobalAlloc(GHND, size); //从堆中分配一定数目的字节数 GHND为分配方式(可移动且初始为0)返回一个新分配的内存对象的句柄。
    LPVOID pBuff = ::GlobalLock(hMem);//锁定内存中指定的内存块,并返回一个地址值,令其指向内存块的起始处。除非用 GlobalUnlock 函数将内存块解锁,否则地址会一直保持有效。

    memcpy(pBuff, pbyteImage, size);

    ::GlobalUnlock(hMem);//解锁内存块
    CreateStreamOnHGlobal(hMem, TRUE, &stream);//从指定内存创建流对象 TRUE:自动释放内存

    image.Load(stream);

    // Drawing
    SetStretchBltMode(pDC->GetSafeHdc() , COLORONCOLOR);
    image.StretchBlt(pDC->GetSafeHdc(),  rect.left,rect.top,rect.Width(),rect.Height(),0,0,image.GetWidth(), image.GetHeight(),SRCCOPY);

    image.Destroy();

    ::GlobalFree(hMem);//释放指定的全局内存块
}


```

猜你喜欢

转载自blog.csdn.net/Mr_sandman1994/article/details/83176284
今日推荐