#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.若能夠從某個接口擷取某特定接口,那麼可以從任意接口都将可以擷取此接口。