/**
 * This file has no copyright assigned and is placed in the Public Domain.
 * This file is part of the w64 mingw-runtime package.
 * No warranty is given; refer to the file DISCLAIMER.PD within this package.
 */
#ifndef _INC_COMUTIL
#define _INC_COMUTIL

#include <ole2.h>

#ifndef _COM_ASSERT
#define _COM_ASSERT(x) ((void)0)
#endif

#define _COM_MEMCPY_S(dest,destsize,src,count) memcpy(dest,src,count)
#define _COM_PRINTF_S_1(dest,destsize,format,arg1) wsprintf(dest,format,arg1)

#ifdef __cplusplus

#pragma push_macro("new")
#undef new

#ifndef WINAPI
#define WINAPI __stdcall
#endif

class _com_error;

void WINAPI _com_issue_error(HRESULT);

class _bstr_t;
class _variant_t;

namespace _com_util {
  inline void CheckError(HRESULT hr) throw() {
    if(FAILED(hr)) { _com_issue_error(hr); }
  }
}

namespace _com_util {
  BSTR WINAPI ConvertStringToBSTR(const char *pSrc);
  char *WINAPI ConvertBSTRToString(BSTR pSrc);
}

class _bstr_t {
public:
  _bstr_t() throw();
  _bstr_t(const _bstr_t &s) throw();
  _bstr_t(const char *s);
  _bstr_t(const wchar_t *s);
  _bstr_t(const _variant_t &var);
  _bstr_t(BSTR bstr,bool fCopy);
  ~_bstr_t() throw();
  _bstr_t &operator=(const _bstr_t &s) throw();
  _bstr_t &operator=(const char *s);
  _bstr_t &operator=(const wchar_t *s);
  _bstr_t &operator=(const _variant_t &var);
  _bstr_t &operator+=(const _bstr_t &s);
  _bstr_t operator+(const _bstr_t &s) const;
  friend _bstr_t operator+(const char *s1,const _bstr_t &s2);
  friend _bstr_t operator+(const wchar_t *s1,const _bstr_t &s2);
  operator const wchar_t *() const throw();
  operator wchar_t *() const throw();
  operator const char *() const;
  operator char *() const;
  bool operator!() const throw();
  bool operator==(const _bstr_t &str) const throw();
  bool operator!=(const _bstr_t &str) const throw();
  bool operator<(const _bstr_t &str) const throw();
  bool operator>(const _bstr_t &str) const throw();
  bool operator<=(const _bstr_t &str) const throw();
  bool operator>=(const _bstr_t &str) const throw();
  BSTR copy(bool fCopy = true) const;
  unsigned int length() const throw();
  void Assign(BSTR s);
  BSTR &GetBSTR();
  BSTR *GetAddress();
  void Attach(BSTR s);
  BSTR Detach() throw();
private:
  class Data_t {
  public:
    Data_t(const char *s);
    Data_t(const wchar_t *s);
    Data_t(BSTR bstr,bool fCopy);
    Data_t(const _bstr_t &s1,const _bstr_t &s2);
    unsigned long AddRef() throw();
    unsigned long Release() throw();
    unsigned long RefCount() const throw();
    operator const wchar_t *() const throw();
    operator const char *() const;
    const wchar_t *GetWString() const throw();
    wchar_t *&GetWString() throw();
    const char *GetString() const;
    BSTR Copy() const;
    void Assign(BSTR s);
    void Attach(BSTR s) throw();
    unsigned int Length() const throw();
    int Compare(const Data_t &str) const throw();
    void *operator new(size_t sz);
  private:
    BSTR m_wstr;
    mutable char *m_str;
    unsigned long m_RefCount;
    Data_t() throw();
    Data_t(const Data_t &s) throw();
    ~Data_t() throw();
    void _Free() throw();
  };
private:
  Data_t *m_Data;
private:
  void _AddRef() throw();
  void _Free() throw();
  int _Compare(const _bstr_t &str) const throw();
};

inline _bstr_t::_bstr_t() throw() : m_Data(NULL) { }

inline _bstr_t::_bstr_t(const _bstr_t &s) throw() : m_Data(s.m_Data) { _AddRef(); }

inline _bstr_t::_bstr_t(const char *s) : m_Data(new Data_t(s)) {
  if(!m_Data) { _com_issue_error(E_OUTOFMEMORY); }
}

inline _bstr_t::_bstr_t(const wchar_t *s) : m_Data(new Data_t(s)) {
  if(!m_Data) { _com_issue_error(E_OUTOFMEMORY); }
}

inline _bstr_t::_bstr_t(BSTR bstr,bool fCopy) : m_Data(new Data_t(bstr,fCopy)) {
  if(!m_Data) { _com_issue_error(E_OUTOFMEMORY); }
}

inline _bstr_t::~_bstr_t() throw() { _Free(); }

inline _bstr_t &_bstr_t::operator=(const _bstr_t &s) throw() {
  if(this!=&s) {
    _Free();
    m_Data = s.m_Data;
    _AddRef();
  }
  return *this;
}

inline _bstr_t &_bstr_t::operator=(const char *s) {
  _COM_ASSERT(!s || static_cast<const char *>(*this)!=s);
  if(!s || static_cast<const char *>(*this)!=s) {
    _Free();
    m_Data = new Data_t(s);
    if(!m_Data) { _com_issue_error(E_OUTOFMEMORY); }
  }
  return *this;
}

inline _bstr_t &_bstr_t::operator=(const wchar_t *s) {
  _COM_ASSERT(!s || static_cast<const wchar_t *>(*this)!=s);
  if(!s || static_cast<const wchar_t *>(*this)!=s) {
    _Free();
    m_Data = new Data_t(s);
    if(!m_Data) { _com_issue_error(E_OUTOFMEMORY); }
  }
  return *this;
}

inline _bstr_t &_bstr_t::operator+=(const _bstr_t &s) {
  Data_t *newData = new Data_t(*this,s);
  if(!newData) { _com_issue_error(E_OUTOFMEMORY); }
  else {
    _Free();
    m_Data = newData;
  }
  return *this;
}

inline _bstr_t _bstr_t::operator+(const _bstr_t &s) const {
  _bstr_t b = *this;
  b += s;
  return b;
}

inline _bstr_t operator+(const char *s1,const _bstr_t &s2) {
  _bstr_t b = s1;
  b += s2;
  return b;
}

inline _bstr_t operator+(const wchar_t *s1,const _bstr_t &s2) {
  _bstr_t b = s1;
  b += s2;
  return b;
}

inline _bstr_t::operator const wchar_t *() const throw() { return (m_Data!=NULL) ? m_Data->GetWString() : NULL; }
inline _bstr_t::operator wchar_t *() const throw() { return const_cast<wchar_t *>((m_Data!=NULL) ? m_Data->GetWString() : NULL); }
inline _bstr_t::operator const char *() const { return (m_Data!=NULL) ? m_Data->GetString() : NULL; }
inline _bstr_t::operator char *() const { return const_cast<char *>((m_Data!=NULL) ? m_Data->GetString() : NULL); }
inline bool _bstr_t::operator!() const throw() { return (m_Data!=NULL) ? !m_Data->GetWString() : true; }
inline bool _bstr_t::operator==(const _bstr_t &str) const throw() { return _Compare(str)==0; }
inline bool _bstr_t::operator!=(const _bstr_t &str) const throw() { return _Compare(str)!=0; }
inline bool _bstr_t::operator<(const _bstr_t &str) const throw() { return _Compare(str)<0; }
inline bool _bstr_t::operator>(const _bstr_t &str) const throw() { return _Compare(str)>0; }
inline bool _bstr_t::operator<=(const _bstr_t &str) const throw() { return _Compare(str)<=0; }
inline bool _bstr_t::operator>=(const _bstr_t &str) const throw() { return _Compare(str)>=0; }
inline BSTR _bstr_t::copy(bool fCopy) const { return (m_Data!=NULL) ? (fCopy ? m_Data->Copy() : m_Data->GetWString()) : NULL; }
inline unsigned int _bstr_t::length() const throw() { return (m_Data!=NULL) ? m_Data->Length() : 0; }
inline void _bstr_t::Assign(BSTR s) {
  _COM_ASSERT(!s || !m_Data || m_Data->GetWString()!=s);
  if(!s || !m_Data || m_Data->GetWString()!=s) {
    _Free();
    m_Data = new Data_t(s,TRUE);
    if(!m_Data) { _com_issue_error(E_OUTOFMEMORY); }
  }
}

inline BSTR &_bstr_t::GetBSTR() {
  if(!m_Data) {
    m_Data = new Data_t(0,FALSE);
    if(!m_Data) { _com_issue_error(E_OUTOFMEMORY); }
  }
  return m_Data->GetWString();
}

inline BSTR *_bstr_t::GetAddress() {
  Attach(0);
  return &m_Data->GetWString();
}

inline void _bstr_t::Attach(BSTR s) {
  _Free();
  m_Data = new Data_t(s,FALSE);
  if(!m_Data) { _com_issue_error(E_OUTOFMEMORY); }
}

inline BSTR _bstr_t::Detach() {
  _COM_ASSERT(m_Data!=NULL && m_Data->RefCount()==1);
  if(m_Data!=NULL && m_Data->RefCount()==1) {
    BSTR b = m_Data->GetWString();
    m_Data->GetWString() = NULL;
    _Free();
    return b;
  } else {
    _com_issue_error(E_POINTER);
    return NULL;
  }
}

inline void _bstr_t::_AddRef() throw() {
  if(m_Data!=NULL) m_Data->AddRef();
}

inline void _bstr_t::_Free() throw() {
  if(m_Data!=NULL) {
    m_Data->Release();
    m_Data = NULL;
  }
}

inline int _bstr_t::_Compare(const _bstr_t &str) const throw() {
  if(m_Data==str.m_Data) return 0;
  if(!m_Data) return -1;
  if(!str.m_Data) return 1;
  return m_Data->Compare(*str.m_Data);
}

inline _bstr_t::Data_t::Data_t(const char *s) : m_str(NULL),m_RefCount(1) {
  m_wstr = _com_util::ConvertStringToBSTR(s);
}

inline _bstr_t::Data_t::Data_t(const wchar_t *s) : m_str(NULL),m_RefCount(1) {
  m_wstr = ::SysAllocString(s);
  if(!m_wstr && s!=NULL) { _com_issue_error(E_OUTOFMEMORY); }
}

inline _bstr_t::Data_t::Data_t(BSTR bstr,bool fCopy) : m_str(NULL),m_RefCount(1) {
  if(fCopy && bstr!=NULL) {
    m_wstr = ::SysAllocStringByteLen(reinterpret_cast<char *>(bstr),::SysStringByteLen(bstr));
    if(!m_wstr) { _com_issue_error(E_OUTOFMEMORY); }
  } else m_wstr = bstr;
}

inline _bstr_t::Data_t::Data_t(const _bstr_t &s1,const _bstr_t &s2) : m_str(NULL),m_RefCount(1) {
  const unsigned int l1 = s1.length();
  const unsigned int l2 = s2.length();
  m_wstr = ::SysAllocStringByteLen(NULL,(l1 + l2) *sizeof(wchar_t));
  if(!m_wstr) {
    _com_issue_error(E_OUTOFMEMORY);
    return;
  }
  const wchar_t *wstr1 = static_cast<const wchar_t *>(s1);
  if(wstr1!=NULL) {
    _COM_MEMCPY_S(m_wstr,(l1 + l2 + 1) *sizeof(wchar_t),wstr1,(l1 + 1) *sizeof(wchar_t));
  }
  const wchar_t *wstr2 = static_cast<const wchar_t *>(s2);
  if(wstr2!=NULL) {
    _COM_MEMCPY_S(m_wstr + l1,(l2 + 1) *sizeof(wchar_t),wstr2,(l2 + 1) *sizeof(wchar_t));
  }
}

inline unsigned long _bstr_t::Data_t::AddRef() throw() {
  InterlockedIncrement(reinterpret_cast<long*>(&m_RefCount));
  return m_RefCount;
}

inline unsigned long _bstr_t::Data_t::Release() throw() {
  unsigned long cRef = InterlockedDecrement(reinterpret_cast<long*>(&m_RefCount));
  if(cRef==0) delete this;
  return cRef;
}

inline unsigned long _bstr_t::Data_t::RefCount() const throw() { return m_RefCount; }
inline _bstr_t::Data_t::operator const wchar_t *() const throw() { return m_wstr; }
inline _bstr_t::Data_t::operator const char *() const { return GetString(); }
inline const wchar_t *_bstr_t::Data_t::GetWString() const throw() { return m_wstr; }
inline wchar_t *&_bstr_t::Data_t::GetWString() throw() { return m_wstr; }
inline const char *_bstr_t::Data_t::GetString() const {
  if(!m_str) m_str = _com_util::ConvertBSTRToString(m_wstr);
  return m_str;
}
inline BSTR _bstr_t::Data_t::Copy() const {
  if(m_wstr!=NULL) {
    BSTR bstr = ::SysAllocStringByteLen(reinterpret_cast<char *>(m_wstr),::SysStringByteLen(m_wstr));
    if(!bstr) { _com_issue_error(E_OUTOFMEMORY); }
    return bstr;
  }
  return NULL;
}
inline void _bstr_t::Data_t::Assign(BSTR s) {
  _Free();
  if(s!=NULL) {
    m_wstr = ::SysAllocStringByteLen(reinterpret_cast<char *>(s),::SysStringByteLen(s));
    m_str = 0;
  }
}
inline void _bstr_t::Data_t::Attach(BSTR s) throw() {
  _Free();
  m_wstr = s;
  m_str = 0;
  m_RefCount = 1;
}
inline unsigned int _bstr_t::Data_t::Length() const throw() { return m_wstr ? ::SysStringLen(m_wstr) : 0; }
inline int _bstr_t::Data_t::Compare(const _bstr_t::Data_t &str) const throw() {
  if(!m_wstr) return str.m_wstr ? -1 : 0;
  if(!str.m_wstr) return 1;
  const unsigned int l1 = ::SysStringLen(m_wstr);
  const unsigned int l2 = ::SysStringLen(str.m_wstr);
  unsigned int len = l1;
  if(len>l2) len = l2;
  BSTR bstr1 = m_wstr;
  BSTR bstr2 = str.m_wstr;
  while (len-->0) {
    if(*bstr1++!=*bstr2++) return bstr1[-1] - bstr2[-1];
  }
  return (l1<l2) ? -1 : (l1==l2) ? 0 : 1;
}

#ifdef _COM_OPERATOR_NEW_THROWS
inline void *_bstr_t::Data_t::operator new(size_t sz) {
  try {
    return ::operator new(sz);
  } catch (...) {
    return NULL;
  }
}
#else
inline void *_bstr_t::Data_t::operator new(size_t sz) {
  return ::operator new(sz);
}
#endif

inline _bstr_t::Data_t::~Data_t() throw() { _Free(); }
inline void _bstr_t::Data_t::_Free() throw() {
  if(m_wstr!=NULL) ::SysFreeString(m_wstr);
  if(m_str!=NULL) delete [] m_str;
}

class _variant_t : public ::tagVARIANT {
public:
  _variant_t() throw();
  _variant_t(const VARIANT &varSrc);
  _variant_t(const VARIANT *pSrc);
  _variant_t(const _variant_t &varSrc);
  _variant_t(VARIANT &varSrc,bool fCopy);
  _variant_t(short sSrc,VARTYPE vtSrc = VT_I2);
  _variant_t(long lSrc,VARTYPE vtSrc = VT_I4);
  _variant_t(float fltSrc) throw();
  _variant_t(double dblSrc,VARTYPE vtSrc = VT_R8);
  _variant_t(const CY &cySrc) throw();
  _variant_t(const _bstr_t &bstrSrc);
  _variant_t(const wchar_t *pSrc);
  _variant_t(const char *pSrc);
  _variant_t(IDispatch *pSrc,bool fAddRef = true) throw();
  _variant_t(bool boolSrc) throw();
  _variant_t(IUnknown *pSrc,bool fAddRef = true) throw();
  _variant_t(const DECIMAL &decSrc) throw();
  _variant_t(BYTE bSrc) throw();
  _variant_t(char cSrc) throw();
  _variant_t(unsigned short usSrc) throw();
  _variant_t(unsigned long ulSrc) throw();
  _variant_t(int iSrc) throw();
  _variant_t(unsigned int uiSrc) throw();
  __MINGW_EXTENSION _variant_t(__int64 i8Src) throw();
  __MINGW_EXTENSION _variant_t(unsigned __int64 ui8Src) throw();
  ~_variant_t() throw();
  operator short() const;
  operator long() const;
  operator float() const;
  operator double() const;
  operator CY() const;
  operator _bstr_t() const;
  operator IDispatch*() const;
  operator bool() const;
  operator IUnknown*() const;
  operator DECIMAL() const;
  operator BYTE() const;
  operator VARIANT() const throw();
  operator char() const;
  operator unsigned short() const;
  operator unsigned long() const;
  operator int() const;
  operator unsigned int() const;
  __MINGW_EXTENSION operator __int64() const;
  __MINGW_EXTENSION operator unsigned __int64() const;
  _variant_t &operator=(const VARIANT &varSrc);
  _variant_t &operator=(const VARIANT *pSrc);
  _variant_t &operator=(const _variant_t &varSrc);
  _variant_t &operator=(short sSrc);
  _variant_t &operator=(long lSrc);
  _variant_t &operator=(float fltSrc);
  _variant_t &operator=(double dblSrc);
  _variant_t &operator=(const CY &cySrc);
  _variant_t &operator=(const _bstr_t &bstrSrc);
  _variant_t &operator=(const wchar_t *pSrc);
  _variant_t &operator=(const char *pSrc);
  _variant_t &operator=(IDispatch *pSrc);
  _variant_t &operator=(bool boolSrc);
  _variant_t &operator=(IUnknown *pSrc);
  _variant_t &operator=(const DECIMAL &decSrc);
  _variant_t &operator=(BYTE bSrc);
  _variant_t &operator=(char cSrc);
  _variant_t &operator=(unsigned short usSrc);
  _variant_t &operator=(unsigned long ulSrc);
  _variant_t &operator=(int iSrc);
  _variant_t &operator=(unsigned int uiSrc);
  __MINGW_EXTENSION _variant_t &operator=(__int64 i8Src);
  __MINGW_EXTENSION _variant_t &operator=(unsigned __int64 ui8Src);
  bool operator==(const VARIANT &varSrc) const throw();
  bool operator==(const VARIANT *pSrc) const throw();
  bool operator!=(const VARIANT &varSrc) const throw();
  bool operator!=(const VARIANT *pSrc) const throw();
  void Clear();
  void Attach(VARIANT &varSrc);
  VARIANT Detach();
  VARIANT &GetVARIANT() throw();
  VARIANT *GetAddress();
  void ChangeType(VARTYPE vartype,const _variant_t *pSrc = NULL);
  void SetString(const char *pSrc);
};

inline _variant_t::_variant_t() throw() { ::VariantInit(this); }
inline _variant_t::_variant_t(const VARIANT &varSrc) {
  ::VariantInit(this);
  _com_util::CheckError(::VariantCopy(this,const_cast<VARIANT*>(&varSrc)));
}
inline _variant_t::_variant_t(const VARIANT *pSrc) {
  if(!pSrc) { _com_issue_error(E_POINTER); }
  else {
    ::VariantInit(this);
    _com_util::CheckError(::VariantCopy(this,const_cast<VARIANT*>(pSrc)));
  }
}
inline _variant_t::_variant_t(const _variant_t &varSrc) {
  ::VariantInit(this);
  _com_util::CheckError(::VariantCopy(this,const_cast<VARIANT*>(static_cast<const VARIANT*>(&varSrc))));
}
inline _variant_t::_variant_t(VARIANT &varSrc,bool fCopy) {
  if(fCopy) {
    ::VariantInit(this);
    _com_util::CheckError(::VariantCopy(this,&varSrc));
  } else {
    _COM_MEMCPY_S(this,sizeof(varSrc),&varSrc,sizeof(varSrc));
    V_VT(&varSrc) = VT_EMPTY;
  }
}
inline _variant_t::_variant_t(short sSrc,VARTYPE vtSrc) {
  if((vtSrc!=VT_I2) && (vtSrc!=VT_BOOL)) {
    _com_issue_error(E_INVALIDARG);
    return;
  }
  if(vtSrc==VT_BOOL) {
    V_VT(this) = VT_BOOL;
    V_BOOL(this) = (sSrc ? VARIANT_TRUE : VARIANT_FALSE);
  } else {
    V_VT(this) = VT_I2;
    V_I2(this) = sSrc;
  }
}
inline _variant_t::_variant_t(long lSrc,VARTYPE vtSrc) {
  if((vtSrc!=VT_I4) && (vtSrc!=VT_ERROR) && (vtSrc!=VT_BOOL)) {
    _com_issue_error(E_INVALIDARG);
    return;
  }
  if(vtSrc==VT_ERROR) {
    V_VT(this) = VT_ERROR;
    V_ERROR(this) = lSrc;
  } else if(vtSrc==VT_BOOL) {
    V_VT(this) = VT_BOOL;
    V_BOOL(this) = (lSrc ? VARIANT_TRUE : VARIANT_FALSE);
  } else {
    V_VT(this) = VT_I4;
    V_I4(this) = lSrc;
  }
}
inline _variant_t::_variant_t(float fltSrc) throw() {
  V_VT(this) = VT_R4;
  V_R4(this) = fltSrc;
}

inline _variant_t::_variant_t(double dblSrc,VARTYPE vtSrc) {
  if((vtSrc!=VT_R8) && (vtSrc!=VT_DATE)) {
    _com_issue_error(E_INVALIDARG);
    return;
  }
  if(vtSrc==VT_DATE) {
    V_VT(this) = VT_DATE;
    V_DATE(this) = dblSrc;
  } else {
    V_VT(this) = VT_R8;
    V_R8(this) = dblSrc;
  }
}
inline _variant_t::_variant_t(const CY &cySrc) throw() {
  V_VT(this) = VT_CY;
  V_CY(this) = cySrc;
}
inline _variant_t::_variant_t(const _bstr_t &bstrSrc) {
  V_VT(this) = VT_BSTR;
  BSTR bstr = static_cast<wchar_t *>(bstrSrc);
  if(!bstr) V_BSTR(this) = NULL;
  else {
    V_BSTR(this) = ::SysAllocStringByteLen(reinterpret_cast<char *>(bstr),::SysStringByteLen(bstr));
    if(!(V_BSTR(this))) { _com_issue_error(E_OUTOFMEMORY); }
  }
}
inline _variant_t::_variant_t(const wchar_t *pSrc) {
  V_VT(this) = VT_BSTR;
  V_BSTR(this) = ::SysAllocString(pSrc);
  if(!(V_BSTR(this)) && pSrc!=NULL) { _com_issue_error(E_OUTOFMEMORY); }
}
inline _variant_t::_variant_t(const char *pSrc) {
  V_VT(this) = VT_BSTR;
  V_BSTR(this) = _com_util::ConvertStringToBSTR(pSrc);
}
inline _variant_t::_variant_t(IDispatch *pSrc,bool fAddRef) throw() {
  V_VT(this) = VT_DISPATCH;
  V_DISPATCH(this) = pSrc;
  if(fAddRef && V_DISPATCH(this)!=NULL) V_DISPATCH(this)->AddRef();
}
inline _variant_t::_variant_t(bool boolSrc) throw() {
  V_VT(this) = VT_BOOL;
  V_BOOL(this) = (boolSrc ? VARIANT_TRUE : VARIANT_FALSE);
}
inline _variant_t::_variant_t(IUnknown *pSrc,bool fAddRef) throw() {
  V_VT(this) = VT_UNKNOWN;
  V_UNKNOWN(this) = pSrc;
  if(fAddRef && V_UNKNOWN(this)!=NULL) V_UNKNOWN(this)->AddRef();
}
inline _variant_t::_variant_t(const DECIMAL &decSrc) throw() {
  V_DECIMAL(this) = decSrc;
  V_VT(this) = VT_DECIMAL;
}
inline _variant_t::_variant_t(BYTE bSrc) throw() {
  V_VT(this) = VT_UI1;
  V_UI1(this) = bSrc;
}
inline _variant_t::_variant_t(char cSrc) throw() {
  V_VT(this) = VT_I1;
  V_I1(this) = cSrc;
}
inline _variant_t::_variant_t(unsigned short usSrc) throw() {
  V_VT(this) = VT_UI2;
  V_UI2(this) = usSrc;
}
inline _variant_t::_variant_t(unsigned long ulSrc) throw() {
  V_VT(this) = VT_UI4;
  V_UI4(this) = ulSrc;
}
inline _variant_t::_variant_t(int iSrc) throw() {
  V_VT(this) = VT_INT;
  V_INT(this) = iSrc;
}
inline _variant_t::_variant_t(unsigned int uiSrc) throw() {
  V_VT(this) = VT_UINT;
  V_UINT(this) = uiSrc;
}
__MINGW_EXTENSION inline _variant_t::_variant_t(__int64 i8Src) throw() {
  V_VT(this) = VT_I8;
  V_I8(this) = i8Src;
}
__MINGW_EXTENSION inline _variant_t::_variant_t(unsigned __int64 ui8Src) throw() {
  V_VT(this) = VT_UI8;
  V_UI8(this) = ui8Src;
}
inline _variant_t::operator short() const {
  if(V_VT(this)==VT_I2) return V_I2(this);
  _variant_t varDest;
  varDest.ChangeType(VT_I2,this);
  return V_I2(&varDest);
}
inline _variant_t::operator long() const {
  if(V_VT(this)==VT_I4) return V_I4(this);
  _variant_t varDest;
  varDest.ChangeType(VT_I4,this);
  return V_I4(&varDest);
}

inline _variant_t::operator float() const {
  if(V_VT(this)==VT_R4) return V_R4(this);
  _variant_t varDest;
  varDest.ChangeType(VT_R4,this);
  return V_R4(&varDest);
}

inline _variant_t::operator double() const {
  if(V_VT(this)==VT_R8) return V_R8(this);
  _variant_t varDest;
  varDest.ChangeType(VT_R8,this);
  return V_R8(&varDest);
}

inline _variant_t::operator CY() const {
  if(V_VT(this)==VT_CY) return V_CY(this);
  _variant_t varDest;
  varDest.ChangeType(VT_CY,this);
  return V_CY(&varDest);
}

inline _variant_t::operator _bstr_t() const {
  if(V_VT(this)==VT_BSTR) return V_BSTR(this);
  _variant_t varDest;
  varDest.ChangeType(VT_BSTR,this);
  return V_BSTR(&varDest);
}

inline _variant_t::operator IDispatch*() const {
  if(V_VT(this)==VT_DISPATCH) {
    if(V_DISPATCH(this)!=NULL) V_DISPATCH(this)->AddRef();
    return V_DISPATCH(this);
  }
  _variant_t varDest;
  varDest.ChangeType(VT_DISPATCH,this);
  if(V_DISPATCH(&varDest)!=NULL) V_DISPATCH(&varDest)->AddRef();
  return V_DISPATCH(&varDest);
}
inline _variant_t::operator bool() const {
  if(V_VT(this)==VT_BOOL) return V_BOOL(this) ? true : false;
  _variant_t varDest;
  varDest.ChangeType(VT_BOOL,this);
  return (V_BOOL(&varDest)==VARIANT_TRUE) ? true : false;
}

inline _variant_t::operator IUnknown*() const {
  if(V_VT(this)==VT_UNKNOWN) {
    if(V_UNKNOWN(this)!=NULL) V_UNKNOWN(this)->AddRef();
    return V_UNKNOWN(this);
  }
  _variant_t varDest;
  varDest.ChangeType(VT_UNKNOWN,this);
  if(V_UNKNOWN(&varDest)!=NULL) V_UNKNOWN(&varDest)->AddRef();
  return V_UNKNOWN(&varDest);
}
inline _variant_t::operator DECIMAL() const {
  if(V_VT(this)==VT_DECIMAL) return V_DECIMAL(this);
  _variant_t varDest;
  varDest.ChangeType(VT_DECIMAL,this);
  return V_DECIMAL(&varDest);
}
inline _variant_t::operator BYTE() const {
  if(V_VT(this)==VT_UI1) return V_UI1(this);
  _variant_t varDest;
  varDest.ChangeType(VT_UI1,this);
  return V_UI1(&varDest);
}
inline _variant_t::operator VARIANT() const throw() { return *(VARIANT*) this; }
inline _variant_t::operator char() const {
  if(V_VT(this)==VT_I1) return V_I1(this);
  _variant_t varDest;
  varDest.ChangeType(VT_I1,this);
  return V_I1(&varDest);
}

inline _variant_t::operator unsigned short() const {
  if(V_VT(this)==VT_UI2) return V_UI2(this);
  _variant_t varDest;
  varDest.ChangeType(VT_UI2,this);
  return V_UI2(&varDest);
}

inline _variant_t::operator unsigned long() const {
  if(V_VT(this)==VT_UI4) return V_UI4(this);
  _variant_t varDest;
  varDest.ChangeType(VT_UI4,this);
  return V_UI4(&varDest);
}
inline _variant_t::operator int() const {
  if(V_VT(this)==VT_INT) return V_INT(this);
  _variant_t varDest;
  varDest.ChangeType(VT_INT,this);
  return V_INT(&varDest);
}
inline _variant_t::operator unsigned int() const {
  if(V_VT(this)==VT_UINT) return V_UINT(this);
  _variant_t varDest;
  varDest.ChangeType(VT_UINT,this);
  return V_UINT(&varDest);
}
__MINGW_EXTENSION inline _variant_t::operator __int64() const {
  if(V_VT(this)==VT_I8) return V_I8(this);
  _variant_t varDest;
  varDest.ChangeType(VT_I8,this);
  return V_I8(&varDest);
}
__MINGW_EXTENSION inline _variant_t::operator unsigned __int64() const {
  if(V_VT(this)==VT_UI8) return V_UI8(this);
  _variant_t varDest;
  varDest.ChangeType(VT_UI8,this);
  return V_UI8(&varDest);
}
inline _variant_t &_variant_t::operator=(const VARIANT &varSrc) {
  _com_util::CheckError(::VariantCopy(this,const_cast<VARIANT*>(&varSrc)));
  return *this;
}
inline _variant_t &_variant_t::operator=(const VARIANT *pSrc) {
  if(!pSrc) { _com_issue_error(E_POINTER); }
  else { _com_util::CheckError(::VariantCopy(this,const_cast<VARIANT*>(pSrc))); }
  return *this;
}
inline _variant_t &_variant_t::operator=(const _variant_t &varSrc) {
  _com_util::CheckError(::VariantCopy(this,const_cast<VARIANT*>(static_cast<const VARIANT*>(&varSrc))));
  return *this;
}
inline _variant_t &_variant_t::operator=(short sSrc) {
  if(V_VT(this)==VT_I2) V_I2(this) = sSrc;
  else if(V_VT(this)==VT_BOOL) V_BOOL(this) = (sSrc ? VARIANT_TRUE : VARIANT_FALSE);
  else {
    Clear();
    V_VT(this) = VT_I2;
    V_I2(this) = sSrc;
  }
  return *this;
}
inline _variant_t &_variant_t::operator=(long lSrc) {
  if(V_VT(this)==VT_I4) V_I4(this) = lSrc;
  else if(V_VT(this)==VT_ERROR) V_ERROR(this) = lSrc;
  else if(V_VT(this)==VT_BOOL) V_BOOL(this) = (lSrc ? VARIANT_TRUE : VARIANT_FALSE);
  else {
    Clear();
    V_VT(this) = VT_I4;
    V_I4(this) = lSrc;
  }
  return *this;
}
inline _variant_t &_variant_t::operator=(float fltSrc) {
  if(V_VT(this)!=VT_R4) {
    Clear();
    V_VT(this) = VT_R4;
  }
  V_R4(this) = fltSrc;
  return *this;
}

inline _variant_t &_variant_t::operator=(double dblSrc)
{
  if(V_VT(this)==VT_R8) {
    V_R8(this) = dblSrc;
  }
  else if(V_VT(this)==VT_DATE) {
    V_DATE(this) = dblSrc;
  }
  else {

    Clear();

    V_VT(this) = VT_R8;
    V_R8(this) = dblSrc;
  }

  return *this;
}

inline _variant_t &_variant_t::operator=(const CY &cySrc)
{
  if(V_VT(this)!=VT_CY) {

    Clear();

    V_VT(this) = VT_CY;
  }

  V_CY(this) = cySrc;

  return *this;
}

inline _variant_t &_variant_t::operator=(const _bstr_t &bstrSrc)
{
  _COM_ASSERT(V_VT(this)!=VT_BSTR || !((BSTR) bstrSrc) || V_BSTR(this)!=(BSTR) bstrSrc);

  Clear();

  V_VT(this) = VT_BSTR;

  if(!bstrSrc) {
    V_BSTR(this) = NULL;
  }
  else {
    BSTR bstr = static_cast<wchar_t *>(bstrSrc);
    V_BSTR(this) = ::SysAllocStringByteLen(reinterpret_cast<char *>(bstr),::SysStringByteLen(bstr));

    if(!(V_BSTR(this))) {
      _com_issue_error(E_OUTOFMEMORY);
    }
  }

  return *this;
}

inline _variant_t &_variant_t::operator=(const wchar_t *pSrc)
{
  _COM_ASSERT(V_VT(this)!=VT_BSTR || !pSrc || V_BSTR(this)!=pSrc);

  Clear();

  V_VT(this) = VT_BSTR;

  if(!pSrc) {
    V_BSTR(this) = NULL;
  }
  else {
    V_BSTR(this) = ::SysAllocString(pSrc);

    if(!(V_BSTR(this))) {
      _com_issue_error(E_OUTOFMEMORY);
    }
  }

  return *this;
}

inline _variant_t &_variant_t::operator=(const char *pSrc)
{
  _COM_ASSERT(V_VT(this)!=(VT_I1 | VT_BYREF) || !pSrc || V_I1REF(this)!=pSrc);

  Clear();

  V_VT(this) = VT_BSTR;
  V_BSTR(this) = _com_util::ConvertStringToBSTR(pSrc);

  return *this;
}

inline _variant_t &_variant_t::operator=(IDispatch *pSrc)
{
  _COM_ASSERT(V_VT(this)!=VT_DISPATCH || pSrc==0 || V_DISPATCH(this)!=pSrc);

  Clear();

  V_VT(this) = VT_DISPATCH;
  V_DISPATCH(this) = pSrc;

  if(V_DISPATCH(this)!=NULL) {

    V_DISPATCH(this)->AddRef();
  }

  return *this;
}

inline _variant_t &_variant_t::operator=(bool boolSrc)
{
  if(V_VT(this)!=VT_BOOL) {

    Clear();

    V_VT(this) = VT_BOOL;
  }

  V_BOOL(this) = (boolSrc ? VARIANT_TRUE : VARIANT_FALSE);

  return *this;
}

inline _variant_t &_variant_t::operator=(IUnknown *pSrc)
{
  _COM_ASSERT(V_VT(this)!=VT_UNKNOWN || !pSrc || V_UNKNOWN(this)!=pSrc);

  Clear();

  V_VT(this) = VT_UNKNOWN;
  V_UNKNOWN(this) = pSrc;

  if(V_UNKNOWN(this)!=NULL) {

    V_UNKNOWN(this)->AddRef();
  }

  return *this;
}

inline _variant_t &_variant_t::operator=(const DECIMAL &decSrc)
{
  if(V_VT(this)!=VT_DECIMAL) {

    Clear();
  }

  V_DECIMAL(this) = decSrc;
  V_VT(this) = VT_DECIMAL;

  return *this;
}

inline _variant_t &_variant_t::operator=(BYTE bSrc)
{
  if(V_VT(this)!=VT_UI1) {

    Clear();

    V_VT(this) = VT_UI1;
  }

  V_UI1(this) = bSrc;

  return *this;
}

inline _variant_t &_variant_t::operator=(char cSrc)
{
  if(V_VT(this)!=VT_I1) {

    Clear();

    V_VT(this) = VT_I1;
  }

  V_I1(this) = cSrc;

  return *this;
}

inline _variant_t &_variant_t::operator=(unsigned short usSrc)
{
  if(V_VT(this)!=VT_UI2) {

    Clear();

    V_VT(this) = VT_UI2;
  }

  V_UI2(this) = usSrc;

  return *this;
}

inline _variant_t &_variant_t::operator=(unsigned long ulSrc)
{
  if(V_VT(this)!=VT_UI4) {

    Clear();

    V_VT(this) = VT_UI4;
  }

  V_UI4(this) = ulSrc;

  return *this;
}

inline _variant_t &_variant_t::operator=(int iSrc)
{
  if(V_VT(this)!=VT_INT) {

    Clear();

    V_VT(this) = VT_INT;
  }

  V_INT(this) = iSrc;

  return *this;
}

inline _variant_t &_variant_t::operator=(unsigned int uiSrc)
{
  if(V_VT(this)!=VT_UINT) {

    Clear();

    V_VT(this) = VT_UINT;
  }

  V_UINT(this) = uiSrc;

  return *this;
}

__MINGW_EXTENSION inline _variant_t &_variant_t::operator=(__int64 i8Src) {
  if(V_VT(this)!=VT_I8) {

    Clear();

    V_VT(this) = VT_I8;
  }

  V_I8(this) = i8Src;

  return *this;
}

__MINGW_EXTENSION inline _variant_t &_variant_t::operator=(unsigned __int64 ui8Src) {
  if(V_VT(this)!=VT_UI8) {

    Clear();

    V_VT(this) = VT_UI8;
  }

  V_UI8(this) = ui8Src;

  return *this;
}

inline bool _variant_t::operator==(const VARIANT &varSrc) const throw() {
  return *this==&varSrc;
}

inline bool _variant_t::operator==(const VARIANT *pSrc) const throw()
{
  if(!pSrc) {
    return false;
  }

  if(this==pSrc) {
    return true;
  }

  if(V_VT(this)!=V_VT(pSrc)) {
    return false;
  }

  switch (V_VT(this)) {
case VT_EMPTY:
case VT_NULL:
  return true;

case VT_I2:
  return V_I2(this)==V_I2(pSrc);

case VT_I4:
  return V_I4(this)==V_I4(pSrc);

case VT_R4:
  return V_R4(this)==V_R4(pSrc);

case VT_R8:
  return V_R8(this)==V_R8(pSrc);

case VT_CY:
  return memcmp(&(V_CY(this)),&(V_CY(pSrc)),sizeof(CY))==0;

case VT_DATE:
  return V_DATE(this)==V_DATE(pSrc);

case VT_BSTR:
  return (::SysStringByteLen(V_BSTR(this))==::SysStringByteLen(V_BSTR(pSrc))) &&
    (memcmp(V_BSTR(this),V_BSTR(pSrc),::SysStringByteLen(V_BSTR(this)))==0);

case VT_DISPATCH:
  return V_DISPATCH(this)==V_DISPATCH(pSrc);

case VT_ERROR:
  return V_ERROR(this)==V_ERROR(pSrc);

case VT_BOOL:
  return V_BOOL(this)==V_BOOL(pSrc);

case VT_UNKNOWN:
  return V_UNKNOWN(this)==V_UNKNOWN(pSrc);

case VT_DECIMAL:
  return memcmp(&(V_DECIMAL(this)),&(V_DECIMAL(pSrc)),sizeof(DECIMAL))==0;

case VT_UI1:
  return V_UI1(this)==V_UI1(pSrc);

case VT_I1:
  return V_I1(this)==V_I1(pSrc);

case VT_UI2:
  return V_UI2(this)==V_UI2(pSrc);

case VT_UI4:
  return V_UI4(this)==V_UI4(pSrc);

case VT_INT:
  return V_INT(this)==V_INT(pSrc);

case VT_UINT:
  return V_UINT(this)==V_UINT(pSrc);

case VT_I8:
  return V_I8(this)==V_I8(pSrc);

case VT_UI8:
  return V_UI8(this)==V_UI8(pSrc);

default:
  _com_issue_error(E_INVALIDARG);

  }

  return false;
}

inline bool _variant_t::operator!=(const VARIANT &varSrc) const throw()
{
  return !(*this==&varSrc);
}

inline bool _variant_t::operator!=(const VARIANT *pSrc) const throw()
{
  return !(*this==pSrc);
}

inline void _variant_t::Clear()
{
  _com_util::CheckError(::VariantClear(this));
}

inline void _variant_t::Attach(VARIANT &varSrc)
{

  Clear();

  _COM_MEMCPY_S(this,sizeof(varSrc),&varSrc,sizeof(varSrc));
  V_VT(&varSrc) = VT_EMPTY;
}

inline VARIANT _variant_t::Detach()
{
  VARIANT varResult = *this;
  V_VT(this) = VT_EMPTY;

  return varResult;
}

inline VARIANT &_variant_t::GetVARIANT() throw()
{
  return *(VARIANT*) this;
}

inline VARIANT *_variant_t::GetAddress() {
  Clear();
  return (VARIANT*) this;
}
inline void _variant_t::ChangeType(VARTYPE vartype,const _variant_t *pSrc) {
  if(!pSrc) pSrc = this;
  if((this!=pSrc) || (vartype!=V_VT(this))) {
    _com_util::CheckError(::VariantChangeType(static_cast<VARIANT*>(this),const_cast<VARIANT*>(static_cast<const VARIANT*>(pSrc)),0,vartype));
  }
}
inline void _variant_t::SetString(const char *pSrc) { operator=(pSrc); }
inline _variant_t::~_variant_t() throw() { ::VariantClear(this); }
inline _bstr_t::_bstr_t(const _variant_t &var) : m_Data(NULL) {
  if(V_VT(&var)==VT_BSTR) {
    *this = V_BSTR(&var);
    return;
  }
  _variant_t varDest;
  varDest.ChangeType(VT_BSTR,&var);
  *this = V_BSTR(&varDest);
}
inline _bstr_t &_bstr_t::operator=(const _variant_t &var) {
  if(V_VT(&var)==VT_BSTR) {
    *this = V_BSTR(&var);
    return *this;
  }
  _variant_t varDest;
  varDest.ChangeType(VT_BSTR,&var);
  *this = V_BSTR(&varDest);
  return *this;
}

extern _variant_t vtMissing;

#ifndef _USE_RAW
#define bstr_t _bstr_t
#define variant_t _variant_t
#endif

#pragma pop_macro("new")

#endif /* __cplusplus */

#endif
