ScopedVariant

class ScopedVariant {

 public:

  // Declaration of a global variant variable that's always VT_EMPTY

  static const VARIANT kEmptyVariant;

 

  // Default constructor.

  ScopedVariant() {

    // This is equivalent to what VariantInit does, but less code.

    var_.vt = VT_EMPTY;

  }

 

  // Constructor to create a new VT_BSTR VARIANT.

  // NOTE: Do not pass a BSTR to this constructor expecting ownership to

  // be transferred

  explicit ScopedVariant(const wchar_t* str);

 

  // Creates a new VT_BSTR variant of a specified length.

  explicit ScopedVariant(const wchar_t* str, UINT length);

 

  // Creates a new integral type variant and assigns the value to

  // VARIANT.lVal (32 bit sized field).

  explicit ScopedVariant(int value, VARTYPE vt = VT_I4);

 

  // VT_DISPATCH

  explicit ScopedVariant(IDispatch* dispatch);

 

  // VT_UNKNOWN

  explicit ScopedVariant(IUnknown* unknown);

 

  // Copies the variant.

  explicit ScopedVariant(const VARIANT& var);

 

  ~ScopedVariant();

 

  inline VARTYPE type() const {

    return var_.vt;

  }

 

  // Give ScopedVariant ownership over an already allocated VARIANT.

  void Reset(const VARIANT& var = kEmptyVariant);

 

  // Releases ownership of the VARIANT to the caller.

  VARIANT Release();

 

  // Swap two ScopedVariant's.

  void Swap(ScopedVariant& var);

 

  // Returns a copy of the variant.

  VARIANT Copy() const;

 

  // The return value is 0 if the variants are equal, 1 if this object is

  // greater than |var|, -1 if it is smaller.

  int Compare(const VARIANT& var, bool ignore_case = false) const;

 

  // Retrieves the pointer address.

  // Used to receive a VARIANT as an out argument (and take ownership).

  // The function DCHECKs on the current value being empty/null.

  // Usage: GetVariant(var.receive());

  VARIANT* Receive();

 

  void Set(const wchar_t* str);

 

  // Setters for simple types.

  void Set(int8 i8);

  void Set(uint8 ui8);

  void Set(int16 i16);

  void Set(uint16 ui16);

  void Set(int32 i32);

  void Set(uint32 ui32);

  void Set(int64 i64);

  void Set(uint64 ui64);

  void Set(float r32);

  void Set(double r64);

  void Set(bool b);

 

  // Creates a copy of |var| and assigns as this instance's value.

  // Note that this is different from the Reset() method that's used to

  // free the current value and assume ownership.

  void Set(const VARIANT& var);

 

  // COM object setters

  void Set(IDispatch* disp);

  void Set(IUnknown* unk);

 

  // SAFEARRAY support

  void Set(SAFEARRAY* array);

 

  // Special setter for DATE since DATE is a double and we already have

  // a setter for double.

  void SetDate(DATE date);

 

  // Allows const access to the contained variant without DCHECKs etc.

  // This support is necessary for the V_XYZ (e.g. V_BSTR) set of macros to

  // work properly but still doesn't allow modifications since we want control

  // over that.

  const VARIANT* operator&() const {

    return &var_;

  }

 

  // Like other scoped classes (e.g scoped_refptr, ScopedComPtr, ScopedBstr)

  // we support the assignment operator for the type we wrap.

  ScopedVariant& operator=(const VARIANT& var);

 

  // A hack to pass a pointer to the variant where the accepting

  // function treats the variant as an input-only, read-only value

  // but the function prototype requires a non const variant pointer.

  // There's no DCHECK or anything here.  Callers must know what they're doing.

  VARIANT* AsInput() const {

    // The nature of this function is const, so we declare

    // it as such and cast away the constness here.

    return const_cast<VARIANT*>(&var_);

  }

 

  // Allows the ScopedVariant instance to be passed to functions either by value

  // or by const reference.

  operator const VARIANT&() const {

    return var_;

  }

 

  // Used as a debug check to see if we're leaking anything.

  static bool IsLeakableVarType(VARTYPE vt);

 

 protected:

  VARIANT var_;

 

 private:

  // Comparison operators for ScopedVariant are not supported at this point.

  // Use the Compare method instead.

  bool operator==(const ScopedVariant& var) const;

  bool operator!=(const ScopedVariant& var) const;

  DISALLOW_COPY_AND_ASSIGN(ScopedVariant);

};

// Global, const instance of an empty variant.
const VARIANT ScopedVariant::kEmptyVariant = { VT_EMPTY };
ScopedVariant::~ScopedVariant() {
  COMPILE_ASSERT(sizeof(ScopedVariant) == sizeof(VARIANT), ScopedVariantSize);
  ::VariantClear(&var_);
}
ScopedVariant::ScopedVariant(const wchar_t* str) {
  var_.vt = VT_EMPTY;
  Set(str);
}
ScopedVariant::ScopedVariant(const wchar_t* str, UINT length) {
  var_.vt = VT_BSTR;
  var_.bstrVal = ::SysAllocStringLen(str, length);
}
ScopedVariant::ScopedVariant(int value, VARTYPE vt) {
  var_.vt = vt;
  var_.lVal = value;
}
ScopedVariant::ScopedVariant(IDispatch* dispatch) {
  var_.vt = VT_EMPTY;
  Set(dispatch);
}
ScopedVariant::ScopedVariant(IUnknown* unknown) {
  var_.vt = VT_EMPTY;
  Set(unknown);
}
ScopedVariant::ScopedVariant(const VARIANT& var) {
  var_.vt = VT_EMPTY;
  Set(var);
}
void ScopedVariant::Reset(const VARIANT& var) {
  if (&var != &var_) {
    ::VariantClear(&var_);
    var_ = var;
  }
}
VARIANT ScopedVariant::Release() {
  VARIANT var = var_;
  var_.vt = VT_EMPTY;
  return var;
}
void ScopedVariant::Swap(ScopedVariant& var) {
  VARIANT tmp = var_;
  var_ = var.var_;
  var.var_ = tmp;
}
VARIANT* ScopedVariant::Receive() {
  DCHECK(!IsLeakableVarType(var_.vt)) << "variant leak. type: " << var_.vt;
  return &var_;
}
VARIANT ScopedVariant::Copy() const {
  VARIANT ret = { VT_EMPTY };
  ::VariantCopy(&ret, &var_);
  return ret;
}
int ScopedVariant::Compare(const VARIANT& var, bool ignore_case) const {
  ULONG flags = ignore_case ? NORM_IGNORECASE : 0;
  HRESULT hr = ::VarCmp(const_cast<VARIANT*>(&var_), const_cast<VARIANT*>(&var),
                        LOCALE_USER_DEFAULT, flags);
  int ret = 0;
  switch (hr) {
    case VARCMP_LT:
      ret = -1;
      break;
    case VARCMP_GT:
    case VARCMP_NULL:
      ret = 1;
      break;
    default:
      // Equal.
      break;
  }
  return ret;
}
void ScopedVariant::Set(const wchar_t* str) {
  DCHECK(!IsLeakableVarType(var_.vt)) << "leaking variant: " << var_.vt;
  var_.vt = VT_BSTR;
  var_.bstrVal = ::SysAllocString(str);
}
void ScopedVariant::Set(int8 i8) {
  DCHECK(!IsLeakableVarType(var_.vt)) << "leaking variant: " << var_.vt;
  var_.vt = VT_I1;
  var_.cVal = i8;
}
void ScopedVariant::Set(uint8 ui8) {
  DCHECK(!IsLeakableVarType(var_.vt)) << "leaking variant: " << var_.vt;
  var_.vt = VT_UI1;
  var_.bVal = ui8;
}
void ScopedVariant::Set(int16 i16) {
  DCHECK(!IsLeakableVarType(var_.vt)) << "leaking variant: " << var_.vt;
  var_.vt = VT_I2;
  var_.iVal = i16;
}
void ScopedVariant::Set(uint16 ui16) {
  DCHECK(!IsLeakableVarType(var_.vt)) << "leaking variant: " << var_.vt;
  var_.vt = VT_UI2;
  var_.uiVal = ui16;
}
void ScopedVariant::Set(int32 i32) {
  DCHECK(!IsLeakableVarType(var_.vt)) << "leaking variant: " << var_.vt;
  var_.vt = VT_I4;
  var_.lVal = i32;
}
void ScopedVariant::Set(uint32 ui32) {
  DCHECK(!IsLeakableVarType(var_.vt)) << "leaking variant: " << var_.vt;
  var_.vt = VT_UI4;
  var_.ulVal = ui32;
}
void ScopedVariant::Set(int64 i64) {
  DCHECK(!IsLeakableVarType(var_.vt)) << "leaking variant: " << var_.vt;
  var_.vt = VT_I8;
  var_.llVal = i64;
}
void ScopedVariant::Set(uint64 ui64) {
  DCHECK(!IsLeakableVarType(var_.vt)) << "leaking variant: " << var_.vt;
  var_.vt = VT_UI8;
  var_.ullVal = ui64;
}
void ScopedVariant::Set(float r32) {
  DCHECK(!IsLeakableVarType(var_.vt)) << "leaking variant: " << var_.vt;
  var_.vt = VT_R4;
  var_.fltVal = r32;
}
void ScopedVariant::Set(double r64) {
  DCHECK(!IsLeakableVarType(var_.vt)) << "leaking variant: " << var_.vt;
  var_.vt = VT_R8;
  var_.dblVal = r64;
}
void ScopedVariant::SetDate(DATE date) {
  DCHECK(!IsLeakableVarType(var_.vt)) << "leaking variant: " << var_.vt;
  var_.vt = VT_DATE;
  var_.date = date;
}
void ScopedVariant::Set(IDispatch* disp) {
  DCHECK(!IsLeakableVarType(var_.vt)) << "leaking variant: " << var_.vt;
  var_.vt = VT_DISPATCH;
  var_.pdispVal = disp;
  if (disp)
    disp->AddRef();
}
void ScopedVariant::Set(bool b) {
  DCHECK(!IsLeakableVarType(var_.vt)) << "leaking variant: " << var_.vt;
  var_.vt = VT_BOOL;
  var_.boolVal = b ? VARIANT_TRUE : VARIANT_FALSE;
}
void ScopedVariant::Set(IUnknown* unk) {
  DCHECK(!IsLeakableVarType(var_.vt)) << "leaking variant: " << var_.vt;
  var_.vt = VT_UNKNOWN;
  var_.punkVal = unk;
  if (unk)
    unk->AddRef();
}
void ScopedVariant::Set(SAFEARRAY* array) {
  DCHECK(!IsLeakableVarType(var_.vt)) << "leaking variant: " << var_.vt;
  if (SUCCEEDED(::SafeArrayGetVartype(array, &var_.vt))) {
    var_.vt |= VT_ARRAY;
    var_.parray = array;
  } else {
    DCHECK(array == NULL) << "Unable to determine safearray vartype";
    var_.vt = VT_EMPTY;
  }
}
void ScopedVariant::Set(const VARIANT& var) {
  DCHECK(!IsLeakableVarType(var_.vt)) << "leaking variant: " << var_.vt;
  if (FAILED(::VariantCopy(&var_, &var))) {
    DLOG(ERROR) << "VariantCopy failed";
    var_.vt = VT_EMPTY;
  }
}
ScopedVariant& ScopedVariant::operator=(const VARIANT& var) {
  if (&var != &var_) {
    VariantClear(&var_);
    Set(var);
  }
  return *this;
}
bool ScopedVariant::IsLeakableVarType(VARTYPE vt) {
  bool leakable = false;
  switch (vt & VT_TYPEMASK) {
    case VT_BSTR:
    case VT_DISPATCH:
    // we treat VT_VARIANT as leakable to err on the safe side.
    case VT_VARIANT:
    case VT_UNKNOWN:
    case VT_SAFEARRAY:
    // very rarely used stuff (if ever):
    case VT_VOID:
    case VT_PTR:
    case VT_CARRAY:
    case VT_USERDEFINED:
    case VT_LPSTR:
    case VT_LPWSTR:
    case VT_RECORD:
    case VT_INT_PTR:
    case VT_UINT_PTR:
    case VT_FILETIME:
    case VT_BLOB:
    case VT_STREAM:
    case VT_STORAGE:
    case VT_STREAMED_OBJECT:
    case VT_STORED_OBJECT:
    case VT_BLOB_OBJECT:
    case VT_VERSIONED_STREAM:
    case VT_BSTR_BLOB:
      leakable = true;
      break;
  }
  if (!leakable && (vt & VT_ARRAY) != 0) {
    leakable = true;
  }
  return leakable;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值