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