#ifndef COMUtilsH
#define COMUtilsH

// standard
#include <string>
// Windows
#include <objbase.h>

class COMException
{
public:
	COMException(HRESULT r) {error = r;}
	
	std::string raison()
	{
		std::string msg = "Erreur COM: ";
		std::string code;
		
		switch(error)
		{
		case E_INVALIDARG:
			code = "Un ou plusieurs arguments sont invalides";
			break;
		case E_ACCESSDENIED:
			code = "Acces refuse";
			break;
		case E_NOINTERFACE:
			code = "L'interface n'existe pas";
			break;
		case E_NOTIMPL:
			code = "la methode n'est pas implementee";
			break;
		case E_OUTOFMEMORY:
			code = "Memoire insuffisante";
			break;
		case E_POINTER:
			code = "Un pointeur invalide a ete utilise";
			break;
		case E_UNEXPECTED:
			code = "inattendue";
			break;
		case E_FAIL:
			code = "echec de la methode (E_FAIL)";
			break;
		default:
			code = "inconnue";
			break;
  }

  msg += code;
  return msg;
  }
  
private:
   HRESULT error;
};


template <class T> class SmartCOMPtr
{
public:
	SmartCOMPtr() : p(0) {}

  virtual ~SmartCOMPtr()
  {
    if(p)
      p->Release();
  }
  
  SmartCOMPtr(const SmartCOMPtr<T>& param)
  {
    p = param.p;
    if(param.p)
      param.p->AddRef();
  }

  T& operator*()
  {
    return *p;
  }
  
  T** operator&()
  {
    return &p;
  }

  T* operator->()
  {
    if(!p)
    {
      COMException ce(E_POINTER);
      throw ce;
    }
    return p;
  }

  SmartCOMPtr<T>& operator=(const SmartCOMPtr<T>& param)
  {
   if(param.p)
	   param.p->AddRef();

    if(p)
      p->Release();

    p = param.p;
	return *this;
  }

private:
  T* p;
};


class COMHelper
{
public:
	static void TestOk(HRESULT r)
	{
		if(r != S_OK)
		{	
			COMException ce(r);
			throw ce;
		}
	}
};

class COMInitializer
{
public:
	COMInitializer()
	{
		COMHelper::TestOk(::CoInitialize(NULL));
	}
	~COMInitializer()
	{
		::CoUninitialize();
	}
};

class COMInitializerEx
{
public:
	COMInitializerEx()
	{
		COMHelper::TestOk(::CoInitializeEx(NULL,COINIT_MULTITHREADED));
	}
	~COMInitializerEx()
	{
		::CoUninitialize();
	}
};


#endif
