scoped_safearray.h 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224
  1. // Copyright 2019 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #ifndef BASE_WIN_SCOPED_SAFEARRAY_H_
  5. #define BASE_WIN_SCOPED_SAFEARRAY_H_
  6. #include <objbase.h>
  7. #include "base/base_export.h"
  8. #include "base/check_op.h"
  9. #include "base/macros.h"
  10. #include "base/optional.h"
  11. #include "base/win/variant_util.h"
  12. namespace base {
  13. namespace win {
  14. // Manages a Windows SAFEARRAY. This is a minimal wrapper that simply provides
  15. // RAII semantics and does not duplicate the extensive functionality that
  16. // CComSafeArray offers.
  17. class BASE_EXPORT ScopedSafearray {
  18. public:
  19. // LockScope<VARTYPE> class for automatically managing the lifetime of a
  20. // SAFEARRAY lock, and granting easy access to the underlying data either
  21. // through random access or as an iterator.
  22. // It is undefined behavior if the underlying SAFEARRAY is destroyed
  23. // before the LockScope.
  24. // LockScope implements std::iterator_traits as a random access iterator, so
  25. // that LockScope is compatible with STL methods that require these traits.
  26. template <VARTYPE ElementVartype>
  27. class BASE_EXPORT LockScope final {
  28. public:
  29. // Type declarations to support std::iterator_traits
  30. using iterator_category = std::random_access_iterator_tag;
  31. using value_type = typename internal::VariantUtil<ElementVartype>::Type;
  32. using difference_type = ptrdiff_t;
  33. using reference = value_type&;
  34. using const_reference = const value_type&;
  35. using pointer = value_type*;
  36. using const_pointer = const value_type*;
  37. LockScope()
  38. : safearray_(nullptr),
  39. vartype_(VT_EMPTY),
  40. array_(nullptr),
  41. array_size_(0U) {}
  42. LockScope(LockScope<ElementVartype>&& other)
  43. : safearray_(std::exchange(other.safearray_, nullptr)),
  44. vartype_(std::exchange(other.vartype_, VT_EMPTY)),
  45. array_(std::exchange(other.array_, nullptr)),
  46. array_size_(std::exchange(other.array_size_, 0U)) {}
  47. LockScope<ElementVartype>& operator=(LockScope<ElementVartype>&& other) {
  48. DCHECK_NE(this, &other);
  49. Reset();
  50. safearray_ = std::exchange(other.safearray_, nullptr);
  51. vartype_ = std::exchange(other.vartype_, VT_EMPTY);
  52. array_ = std::exchange(other.array_, nullptr);
  53. array_size_ = std::exchange(other.array_size_, 0U);
  54. return *this;
  55. }
  56. ~LockScope() { Reset(); }
  57. VARTYPE Type() const { return vartype_; }
  58. size_t size() const { return array_size_; }
  59. pointer begin() { return array_; }
  60. pointer end() { return array_ + array_size_; }
  61. const_pointer begin() const { return array_; }
  62. const_pointer end() const { return array_ + array_size_; }
  63. pointer data() { return array_; }
  64. const_pointer data() const { return array_; }
  65. reference operator[](int index) { return at(index); }
  66. const_reference operator[](int index) const { return at(index); }
  67. reference at(size_t index) {
  68. DCHECK_NE(array_, nullptr);
  69. DCHECK_LT(index, array_size_);
  70. return array_[index];
  71. }
  72. const_reference at(size_t index) const {
  73. return const_cast<LockScope<ElementVartype>*>(this)->at(index);
  74. }
  75. private:
  76. LockScope(SAFEARRAY* safearray,
  77. VARTYPE vartype,
  78. pointer array,
  79. size_t array_size)
  80. : safearray_(safearray),
  81. vartype_(vartype),
  82. array_(array),
  83. array_size_(array_size) {}
  84. void Reset() {
  85. if (safearray_)
  86. SafeArrayUnaccessData(safearray_);
  87. safearray_ = nullptr;
  88. vartype_ = VT_EMPTY;
  89. array_ = nullptr;
  90. array_size_ = 0U;
  91. }
  92. SAFEARRAY* safearray_;
  93. VARTYPE vartype_;
  94. pointer array_;
  95. size_t array_size_;
  96. friend class ScopedSafearray;
  97. DISALLOW_COPY_AND_ASSIGN(LockScope);
  98. };
  99. explicit ScopedSafearray(SAFEARRAY* safearray = nullptr)
  100. : safearray_(safearray) {}
  101. // Move constructor
  102. ScopedSafearray(ScopedSafearray&& r) noexcept : safearray_(r.safearray_) {
  103. r.safearray_ = nullptr;
  104. }
  105. // Move operator=. Allows assignment from a ScopedSafearray rvalue.
  106. ScopedSafearray& operator=(ScopedSafearray&& rvalue) {
  107. Reset(rvalue.Release());
  108. return *this;
  109. }
  110. ~ScopedSafearray() { Destroy(); }
  111. // Creates a LockScope for accessing the contents of a
  112. // single-dimensional SAFEARRAYs.
  113. template <VARTYPE ElementVartype>
  114. base::Optional<LockScope<ElementVartype>> CreateLockScope() const {
  115. if (!safearray_ || SafeArrayGetDim(safearray_) != 1)
  116. return base::nullopt;
  117. VARTYPE vartype;
  118. HRESULT hr = SafeArrayGetVartype(safearray_, &vartype);
  119. if (FAILED(hr) ||
  120. !internal::VariantUtil<ElementVartype>::IsConvertibleTo(vartype)) {
  121. return base::nullopt;
  122. }
  123. typename LockScope<ElementVartype>::pointer array = nullptr;
  124. hr = SafeArrayAccessData(safearray_, reinterpret_cast<void**>(&array));
  125. if (FAILED(hr))
  126. return base::nullopt;
  127. const size_t array_size = GetCount();
  128. return LockScope<ElementVartype>(safearray_, vartype, array, array_size);
  129. }
  130. void Destroy() {
  131. if (safearray_) {
  132. HRESULT hr = SafeArrayDestroy(safearray_);
  133. DCHECK_EQ(S_OK, hr);
  134. safearray_ = nullptr;
  135. }
  136. }
  137. // Give ScopedSafearray ownership over an already allocated SAFEARRAY or
  138. // nullptr.
  139. void Reset(SAFEARRAY* safearray = nullptr) {
  140. if (safearray != safearray_) {
  141. Destroy();
  142. safearray_ = safearray;
  143. }
  144. }
  145. // Releases ownership of the SAFEARRAY to the caller.
  146. SAFEARRAY* Release() {
  147. SAFEARRAY* safearray = safearray_;
  148. safearray_ = nullptr;
  149. return safearray;
  150. }
  151. // Retrieves the pointer address.
  152. // Used to receive SAFEARRAYs as out arguments (and take ownership).
  153. // This function releases any existing references because it will leak
  154. // the existing ref otherwise.
  155. // Usage: GetSafearray(safearray.Receive());
  156. SAFEARRAY** Receive() {
  157. Destroy();
  158. return &safearray_;
  159. }
  160. // Returns the number of elements in a dimension of the array.
  161. size_t GetCount(UINT dimension = 0) const {
  162. DCHECK(safearray_);
  163. // Initialize |lower| and |upper| so this method will return zero if either
  164. // SafeArrayGetLBound or SafeArrayGetUBound returns failure because they
  165. // only write to the output parameter when successful.
  166. LONG lower = 0;
  167. LONG upper = -1;
  168. DCHECK_LT(dimension, SafeArrayGetDim(safearray_));
  169. HRESULT hr = SafeArrayGetLBound(safearray_, dimension + 1, &lower);
  170. DCHECK(SUCCEEDED(hr));
  171. hr = SafeArrayGetUBound(safearray_, dimension + 1, &upper);
  172. DCHECK(SUCCEEDED(hr));
  173. return (upper - lower + 1);
  174. }
  175. // Returns the internal pointer.
  176. SAFEARRAY* Get() const { return safearray_; }
  177. // Forbid comparison of ScopedSafearray types. You should never have the same
  178. // SAFEARRAY owned by two different scoped_ptrs.
  179. bool operator==(const ScopedSafearray& safearray2) const = delete;
  180. bool operator!=(const ScopedSafearray& safearray2) const = delete;
  181. private:
  182. SAFEARRAY* safearray_;
  183. DISALLOW_COPY_AND_ASSIGN(ScopedSafearray);
  184. };
  185. } // namespace win
  186. } // namespace base
  187. #endif // BASE_WIN_SCOPED_SAFEARRAY_H_