COM
Example 1
#include <iostream>
using namespace std;
#define interface struct
interface IX
{
virtual void Fx1(void) = 0;
virtual void Fx2(void) = 0;
};
interface IY
{
virtual void Fy1(void) = 0;
virtual void Fy2(void) = 0;
};
class CoA : public IX, public IY
{
public:
virtual void Fx1(void) { cout << "CoA::Fx1" << endl; }
virtual void Fx2(void) { cout << "CoA::Fx2" << endl; }
virtual void Fy1(void) { cout << "CoA::Fy1" << endl; }
virtual void Fy2(void) { cout << "CoA::Fy2" << endl; }
};
int main(int argc, char *argv[])
{
cout << "Client: Create an instance of componenet." << endl;
CoA *pA = new CoA;
cout << "Client: Use the IX interface." << endl;
IX *pIX = pA;
pIX->Fx1();
pIX->Fx2();
cout << "Client: Use the IY interface." << endl;
IY *pIY = pA;
pIY->Fy1();
pIY->Fy2();
cout << "Client: Delete the component." << endl;
delete pA;
return 0;
}
Example 2
#include <iostream>
using namespace std;
// Definitions
#define interface struct
// Microsoft-specific extension, use standard/Pascal calling convension (function clear stack)
// different from __cdecl, C calling conversion (caller clear stack)
#define __stdcall
// for 32-bit platform
typedef unsigned char BYTE;
typedef unsigned short WORD;
typedef unsigned int DWORD;
typedef long LONG;
typedef unsigned long ULONG;
struct GUID {
DWORD Data1;
WORD Data2;
WORD Data3;
BYTE Data4[8];
};
inline bool operator==(const GUID& lhs, const GUID& rhs)
{
return !memcmp(&lhs, &rhs, sizeof(GUID));
}
typedef GUID IID;
typedef LONG HRESULT;
const HRESULT S_OK = 0;
const HRESULT E_NOINTERFACE = 0x80004002;
inline bool SUCCEEDED(HRESULT status) { return (status >= 0); }
// reference counting increment/decrement, currently multithreading is not supporting
ULONG __stdcall InterlockedIncrement(ULONG *cRef)
{
(*cRef)++;
return *cRef;
}
ULONG __stdcall InterlockedDecrement(ULONG *cRef)
{
(*cRef)--;
return *cRef;
}
// Interfaces
interface IUnknown
{
virtual HRESULT __stdcall QueryInterface(const IID& iid, void **ppv) = 0;
virtual ULONG __stdcall AddRef(void) = 0;
virtual ULONG __stdcall Release(void) = 0;
};
// Cannot use virtual inheritance as this result COM-incompatible virtual function table
interface IX : IUnknown
{
virtual void __stdcall Fx(void) = 0;
};
interface IY : IUnknown
{
virtual void __stdcall Fy(void) = 0;
};
interface IZ : IUnknown
{
virtual void __stdcall Fz(void) = 0;
};
// IIDs
// {00000000-0000-0000-C000-000000000046}
static const IID IID_IUnknown =
{0x00000000, 0x0000, 0x0000,
{0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46} };
// {12345678-9ABC-DEF0-1234-56789ABCDEF0}
static const IID IID_IX =
{0x12345678, 0x9ABC, 0xDEF0,
{0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC, 0xDE, 0xF0} };
// {23456789-ABCD-EF01-2345-6789ABCDEF01}
static const IID IID_IY =
{0x23456789, 0xABCD, 0xEF01,
{0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF, 0x01} };
// {3456789A-BCDE-F012-3456-789ABCDEF012}
static const IID IID_IZ =
{0x3456789A, 0xBCDE, 0xF012,
{0x34, 0x56, 0x78, 0x9A, 0xBC, 0xDE, 0xF0, 0x12} };
// CoClass (Component)
class CoA : public IX, public IY
{
public:
CoA() : m_cRef(0) { }
~CoA() { cout << "CoA: Destroy self." << endl; }
private:
// private as client will never invoke these methods through CoClass
virtual HRESULT __stdcall QueryInterface(const IID& iid, void **ppv);
virtual ULONG __stdcall AddRef(void);
virtual ULONG __stdcall Release(void);
virtual void __stdcall Fx(void) { cout << "CoA::Fx" << endl; }
virtual void __stdcall Fy(void) { cout << "CoA::Fy" << endl; }
ULONG m_cRef;
};
HRESULT __stdcall CoA::QueryInterface(const IID& iid, void **ppv)
{
if (iid == IID_IUnknown)
{
cout << "QueryInterface: Return pointer to IUnknown." << endl;
// static_cast<IUnknown*> is ambiguous as there are 2 copy of IUnknown class in CoA
// choose one and consistent throughout the implementation:
// static_cast<IUnknown*>(static_cast<IX*>(this)) or
// static_cast<IUnknown*>(static_cast<IY*>(this))
// here choose IX's IUnknown, so simply
*ppv = static_cast<IX*>(this);
}
else if (iid == IID_IX)
{
cout << "QueryInterface: Return pointer to IX." << endl;
*ppv = static_cast<IX*>(this);
}
else if (iid == IID_IY)
{
cout << "QueryInterface: Return pointer to IY." << endl;
*ppv = static_cast<IY*>(this);
}
else
{
cout << "QueryInterface: Interface not supported." << endl;
*ppv = NULL; // COM spec, prevent client accidentally use the invalid pointer as interface
return E_NOINTERFACE;
}
// temporary interprete the pointer as IUnknown to call AddRef
reinterpret_cast<IUnknown*>(*ppv)->AddRef(); // successful query, add reference count
return S_OK;
}
ULONG __stdcall CoA::AddRef(void)
{
cout << "CoA: AddRef = " << m_cRef+1 << "." << endl;
return InterlockedIncrement(&m_cRef); // increment reference count taken threading into account
}
ULONG __stdcall CoA::Release(void)
{
cout << "CoA: Release = " << m_cRef-1 << "." << endl;
if (InterlockedDecrement(&m_cRef) == 0)
{
delete this;
return 0;
}
return m_cRef;
}
IUnknown* CreateInstance(void)
{
IUnknown *pI = static_cast<IX*>(new CoA); // if choose IY's IUnknown, cast to IY*
pI->AddRef(); // add reference count
return pI;
}
// Client
int main(int argc, char *argv[])
{
HRESULT hr;
cout << "Client: Create an instance of componenet." << endl;
IUnknown *pIUnknown = CreateInstance(); // implicitly call AddRef
cout << "Client: Get IX interface." << endl;
IX *pIX = NULL; // in case CoClass not follow COM spec set it to NULL when fail to query
hr = pIUnknown->QueryInterface(IID_IX, (void**)&pIX); // implicitly call AddRef if success
if (SUCCEEDED(hr))
{
cout << "Client: Succeeded getting IX." << endl;
pIX->Fx();
}
cout << "Client: Get IY interface." << endl;
IY *pIY = NULL;
hr = pIUnknown->QueryInterface(IID_IY, (void**)&pIY);
if (SUCCEEDED(hr))
{
cout << "Client: Succeeded getting IY." << endl;
pIY->Fy();
}
cout << "Client: Ask for unsupported interface." << endl;
IZ *pIZ = NULL;
hr = pIUnknown->QueryInterface(IID_IZ, (void**)&pIZ);
if (SUCCEEDED(hr))
{
cout << "Client: Succeeded getting unsupported IZ!" << endl;
pIZ->Fz();
// release it when no more using this interface pointer later, will decrease reference count
// should not place it outside the SUCCEEDED test as QueryInterface only increase count when
// success
pIZ->Release();
}
else
{
cout << "Client: Could not get unsupported interface." << endl;
}
cout << "Client: Get IY from IX." << endl;
IY *pIYFromIX = NULL;
hr = pIX->QueryInterface(IID_IY, (void**)&pIYFromIX);
pIX->Release(); // "destroy" pIX as it is no more use in the code
if (SUCCEEDED(hr))
{
cout << "Client: Succeeded getting IY." << endl;
pIYFromIX->Fy();
pIYFromIX->Release();
}
cout << "Client: Get IUnknown from IY." << endl;
IUnknown *pIUnknownFromIY = NULL;
hr = pIY->QueryInterface(IID_IUnknown, (void**)&pIUnknownFromIY);
pIY->Release(); // so now can safely release pIY
if (SUCCEEDED(hr))
{
cout << "Are the IUnknown pointers equal? ";
if (pIUnknownFromIY == pIUnknown)
{
cout << "Yes, pIUnknownFromIY == pIUnknown." << endl;
}
else
{
cout << "No, pIUnknownFromIY != pIUnknown!" << endl;
}
pIUnknownFromIY->Release();
}
cout << "Client: Delete the component." << endl;
// since pIUnknown is the last interface pointer using CoA, release it will decrease reference
// count to 0 and Release will delete the component
pIUnknown->Release();
return 0;
}
Index