天天看点

COM学习笔记(十二):编程工作的简化

1、你可能忘记进行引用计数或者忘记释放某个组件上接口的指针。

2、即使你在该调用Release的时候调用了它,在程序中却不一定会真正调用它,因为发生异常后C++的异常处理程序不会调用Release以释放此COM组件。

3、一对QueryInterface调用极易使函数中有用的代码黯然失色。

4、其次,QueryInterface不是类型安全的,原因在于(void**)。例如:

IZ* pIZ;

pIX->QueryInterface(IID_IY,(void**)&pIZ);

虽然将一个IY接口指针赋给了一个IZ接口指针,但编译仍然会通过。

为解决以上问题,可以通过封装来解决。一种方法是:使用智能指针类来封装接口指针。另一种方法是通过包装类对接口本身进行封装。

一:智能接口指针:

智能接口指针将把引用计数这类细节隐藏起来,并且当程序的执行离开了智能接口指针的作用域后,相应的接口将被释放掉。一个智能指针实际上就是一个重载了操作符->的类。智能接口指针类包含指向另外一个对象的指针。当用户调用智能指针上的->操作符时,智能指针把此调用转发给它所包含的指针所指的对象。包含的指针将是指向一个接口的。

A simple example:

class CFoo{

public:

virtual void Bar();

};

class CFooPointer{

public:

CFooPointer(CFoo* p){m_p = p;}

CFoo* operator ->(){return m_p;}

private:

CFoo *m_p;

};

.......

void Funky(CFoo* pFoo){

CFooPointer spFoo(pFoo);

spFoo->Bar();

}

//实现一个接口指针类IPtr:

template <class T,const IID* piid>

class IPtr{

public:

IPtr(){ m_pI = NULL;}

IPtr(T* lp){

m_pI = lp;

if(m_pI != NULL)   m_pI->AddRef();

}

IPtr(IUnknown* pI){

m_pI = NULL;

if(pI != NULL){

pI->QueryInterface(*piid,(void**)&m_pI);

}

}

~IPtr(){Release();}

void Release(){

if(m_pI != NULL){

T* pOld = m_pI;

m_pI = NULL;

pOld->Release();

}

}

operator T*(){ return m_pI; }

T& operator*(){assert(m_pI != NULL); return *m_pI;}

T** operator&(){assert(m_pI != NULL); return &m_pI;}

T* operator->(){assert(m_pIY != NULL); return m_pI};

T* operator=(T* pI){

if(m_pI != pI){

IUnknown* pOld = m_pI;

m_pI = pI;

if(m_pI != NULL){

m_pI -> AddRef();

}

if(pOld != NULL){

pOld->Release();

}

return m_pI;

}

T* operator = (IUnknown* pI){

IUnknown* pOld = m_pI;

m_pI = NULL;

if(pI != NULL){

HRESULT hr = pI->QueryInterface(*piid,(void**)&m_pI);

assert(SUCCEEDED(hr) && (m_pI != NULL));

}

if(pOld != NULL){

pOld->Release();

}

return m_pI;

}

BOOL operator ! (){

return (m_pI == NULL)?TRUE:FALSE;

}

const IID& iid(){

return *piid;

}

private:

T* m_pI;

};

//test

void main(){

IPtr<IX,&IID_IX> spIX;

HRESULT hr = ::CoCreateInstance(CLSID_COMPONENT1, NULL, CLSCTX_ALL,spIX.iid() ,(void**)&spIX);

if(SUCCEEDED(hr)){

spIX->Fx();

}

}

COM学习笔记(十二):编程工作的简化

//test

void Fuzzy(IX* pIX1,IX* pIX2){

IPtr<IX,IID_IX> spIX;

spIX = pIX1;

spIX->Fx();

spIX = pIX2;

spIX->Fx();

}

//test.转换操作符,将一个IPtr对象赋给同类型的另一个IPtr对象。

typedef IPtr<IX,IID_IX> SPIX;

SPIX g_spIX;

void Wuzzy(SPIX spIX){

g_spIX = spIX;

}

//test.将另外一个不同类型的接口指针赋给一个智能指针,赋值操作符将自动调用QueryInterface。

void WsaABear(IY* pIY){

IPtr<IX,IID_IX> spIX;

spIX = pIY;

if(spIX)   spIX->Fx();

}

COM学习笔记(十二):编程工作的简化
COM学习笔记(十二):编程工作的简化
COM学习笔记(十二):编程工作的简化
COM学习笔记(十二):编程工作的简化
COM学习笔记(十二):编程工作的简化

继续阅读