scoped_safearray.h 7.2 KB

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