COM学习笔记(一):入门及QueryInterface

来源:互联网 发布:本地直通车软件 编辑:程序博客网 时间:2024/06/03 08:04

#include <objbase.h>定义了 ->          #define interface struct

#include <windef.h>定义了  ->#define pascal __stdcall

//*****************************************************************************

//COM雏形之前身

 #include <iostream.h>

 #include <objbase.h>

  trace(const char* pMsg){

cout<<pMsg<<endl;

}

 interface IX{

  virtual void __stdcall Fx1() = 0;

virtual void __stdcall Fx2() = 0;

};

 interface IY{

virtual void __stdcall Fy1() = 0;

virtual void __stdcall Fy2() = 0;

};

 class CA : public IX,public IY{

 public:

virtual void __stdcall Fx1(){cout<<"CA::Fx1"<<endl;}

virtual void __stdcall Fx2(){cout<<"CA::Fx2"<<endl;}

virtual void __stdcall Fy1(){cout<<"CA::Fy1"<<endl;}

virtual void __stdcall Fy2(){cout<<"CA::Fy2"<<endl;}

};

 int main(){

 trace("Client: Create an instance of the component.");

CA *pA = new CA;

 IX *pIX = pA;

trace("Client:Use the IX interface.");

pIX->Fx1();

pIX->Fx2();

 IY *pIY = pA;

trace("Client:Use the IY interface.");

pIY->Fy1();

pIY->Fy2();

 race("Client: Delete the component.");

 delete pA;

 return 0;

}

总结:

一:COM接口在C++中是用纯抽象基类实现的。

二:一个COM组件可以提供多个接口。

三:一个C++类可以使用多继承来实现一个可以提供多个接口的组件。

四:用__stdcall标记的函数将使用标准的调用约定,即 这些函数将在返回到调用者之前将参数从栈中删除。Microsoft平台上COM接口所提供的所有函数使用的军事标准的调用约定。

 //*****************************************************************************

 定义一个纯抽象基类也就是定义了相应的内存结构。但此内存只是在派生类中实现此抽象基类时才会被分配。当派生类继承一个抽象基类时,它将继承此内存结构。COM接口的内存结构同C++编译器为抽象基类所生成的内存结构是相同的。

所有的COM接口都必须继承一个名为IUnknown的接口。这意味着所有COM接口的前三项都是相同的,其中保存的是IUnknown中三个成员函数的实现的地址。

 //*****************************************************************************

Interface IUnknown{

HRESULT __stdcall QueryInterface(const IID& iid,void** ppv) = 0;

virtual ULONG __stdcall AddRef() = 0;

virtual ULONG __stdcall Release() = 0;

};

1) 接口查询:定制QueryInterface,客户调用之(若支持,返回一个指向此接口的指针,否则返回一个错误代码)

若某个接口的vtbl中的前三个函数不是IUnknown的三个成员函数,它将不是一个COM接口。

2) 获取IUknown指针:IUnknown* CreateInstance();它可以建立一个组件并返回一个IUnknown指针,而不必再使用new操作符。(需要自己定制)

eg

void foo(IUnknown* pI){

IX* pIX = NULL;

HRESULT hr = pI->QueryInterface(IID_IX,(void**)&pIX);

If(SUCCEEDED(hr)){

pIX->Fx();

}

}

HRESULT __stdcall CA::QueryInterface(const IID& iid,void**ppv){

 if(iid == IID_IUnknown){

*ppv = static_cast<IX*>(this);

}

else if(iid == IID_IX){

*ppv = static_cast<IX*>(this);

}

else if(iid == IID_IY){

*ppv = static_cast<IY*>(this);

}

else{

*ppv = NULL;

return E_NOINTERFACE;

}

static_cast<IUnknown*>(*ppv)->AddRef();

return S_OK;

}

 //*****************************************************************************

 一个完整的例子:

// IUnknown.cpp

#include <iostream.h>

#include <objbase.h>

 void trace(const char* msg){cout<<msg<<endl;}

interface IX : IUnknown{

virtual void __stdcall Fx() = 0;

};

interface IY : IUnknown{

virtual void __stdcal Fy() = 0;

};

interface IZ : IUnknown{

virtual void __stdcall Fz() = 0;

};

extern const IID IID_IX;

extern const IID IID_IY;

extern const IID IID_IZ;

class CA : public IX,

   public IY{

virtual HRESULT __stdcall QueryInterface(const IID& IID,void** ppv);

virtual ULONG __stdcall AddRef(){return 0;}

virtual ULONG __stdcall Release(){return 0;}

 virtual void __stdcall Fx(){cout<<"Fx"<<endl;}

virtual void __stdcall Fy(){cout<<"Fy"<<endl;}

};

HRESULT __stdcall CA::QueryInterface(const IID& iid,void ** ppv){


if(iid == IID_IUnknown){

trace("QueryInterface: Return pointer to IUknown.");

*ppv = static_cast<IX*>(this);

}else if(iid == IID_IX){

trace("QueryInterface: Return pointer toIX.");

*ppv = static_cast<IX*>(this);

}else if(iid == IID_IY){

trace("QueryInterface: Return pointer toIY.");

*ppv = static_cast<IY*>(this);

}else{
trace("QueryInterface:Interface not supported.");

*ppv = NULL;

return E_NOINTERFACE;

}

reinterpret_cast<IUnknown*>(*ppv)->AddRef();

return S_OK;

}

IUnknown* CreateInstance(){

IUnknown* pI = static_cast<IX*>(new CA);

pI->AddRef();

return pI;

}

static const IID IID_IX = {0x32bb8320,0xb41b,0x11cf,{0xa6,0xbb,0x0,0x80,0xc7,0xb2,0xd6,0x82}};

static const IID IID_IY = {0x32bb8321,0xb41b,0x11cf,{0xa6,0xbb,0x0,0x80,0xc7,0xb2,0xd6,0x82}};

static const IID IID _IZ =  {0x32bb8322,0xb41b,0x11cf,{0xa6,0xbb,0x0,0x80,0xc7,0xb2,0xd6,0x82}};

// Client

int main(){

HRESULT hr;

trace("Client:Get an IUnknown pointer.");

IUnknown* pInknown = CreateInstance();

trace("Client:Get interface IX.");

IX* pIX = NULL;

hr = pIUnknown->QueryInterface(IID_IX,(void **)&pIX);

if(SUCCEEDED(hr)){

trace("Client:Succeeded getting IX.");

pIX->Fx();

}

trace("Client: Get interface IY.");

IX* pIY = NULL;

hr = pIUnknown->QueryInterface(IID_IY,(void **)&pIY);

if(SUCCEEDED(hr)){

trace("Client: Succeeded getting IY.");

pIX->Fy();

}

  trace("Client:Ask for an unsupported interface.");

IZ* pIZ = NULL;

hr = pIUnknown->QueryInterface(IID_IZ,(void**)&pIZ);

if(SUCCEEDED(hr)){

trace("Client:Succeeded in getting interface IZ.");

pIZ->Fz();

}else{

trace("Client:Could not get interface IZ.");

trace("Client:Get interface IY from interface IX.");

IY* pIYfromIX = NULL;

hr = pIX->QueryInterface(IID_IY,(void **)&pIYfromIX);

if(SUCCEEDED(hr)){

trace("Client:  Succeeded getting IY.");

pIyfromIX->Fy();

}

trace("Client:Get interface IUnknown from IY.");

IUnknown* pIUnknownFromIY = NULL;

hr = pIY->QueryInterface(IID_IUnknown,(void**)&pIUnknownFromIY);

if(SUCCEEDED(hr)){

cout<<"Are the IUnknown pointers equal?";

if(pIUnknownFromIY == pIUnknwon){

cout<<"Yes,pUnknownFromIY == pIUnknown."<<endl;

}else{

cout<<"No,pIUnknownFromIY != pIUnknown."<<endl;

}

}

delete pIUnknown;

return 0;

}

//*****************************************************************************

 QueryInterface的实现规则:

1.QueryInterface返回的总是同一IUnknown指针。

2.若客户曾经获取过某个接口,那么它将总能获取此接口。

3.客户可以再次获取已经拥有的接口。

4.客户可以返回到起始接口。

5.若能够从某个接口获取某特定接口,那么可以从任意接口都将可以获取此接口。

  

 

0 0