comptr.h 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113
  1. #ifndef COMMON_COMPTR_H
  2. #define COMMON_COMPTR_H
  3. #include <cstddef>
  4. #include <memory>
  5. #include <type_traits>
  6. #include <utility>
  7. #include <variant>
  8. #define WIN32_LEAN_AND_MEAN
  9. #include <windows.h>
  10. #include <objbase.h>
  11. struct ComWrapper {
  12. HRESULT mStatus{};
  13. ComWrapper(void *reserved, DWORD coinit)
  14. : mStatus{CoInitializeEx(reserved, coinit)}
  15. { }
  16. ComWrapper(DWORD coinit=COINIT_APARTMENTTHREADED)
  17. : mStatus{CoInitializeEx(nullptr, coinit)}
  18. { }
  19. ComWrapper(ComWrapper&& rhs) { mStatus = std::exchange(rhs.mStatus, E_FAIL); }
  20. ComWrapper(const ComWrapper&) = delete;
  21. ~ComWrapper() { if(SUCCEEDED(mStatus)) CoUninitialize(); }
  22. ComWrapper& operator=(ComWrapper&& rhs)
  23. {
  24. if(SUCCEEDED(mStatus))
  25. CoUninitialize();
  26. mStatus = std::exchange(rhs.mStatus, E_FAIL);
  27. return *this;
  28. }
  29. ComWrapper& operator=(const ComWrapper&) = delete;
  30. [[nodiscard]]
  31. HRESULT status() const noexcept { return mStatus; }
  32. explicit operator bool() const noexcept { return SUCCEEDED(status()); }
  33. void uninit()
  34. {
  35. if(SUCCEEDED(mStatus))
  36. CoUninitialize();
  37. mStatus = E_FAIL;
  38. }
  39. };
  40. template<typename T>
  41. struct ComPtr {
  42. using element_type = T;
  43. static constexpr bool RefIsNoexcept{noexcept(std::declval<T&>().AddRef())
  44. && noexcept(std::declval<T&>().Release())};
  45. ComPtr() noexcept = default;
  46. ComPtr(const ComPtr &rhs) noexcept(RefIsNoexcept) : mPtr{rhs.mPtr}
  47. { if(mPtr) mPtr->AddRef(); }
  48. ComPtr(ComPtr&& rhs) noexcept : mPtr{rhs.mPtr} { rhs.mPtr = nullptr; }
  49. ComPtr(std::nullptr_t) noexcept { }
  50. explicit ComPtr(T *ptr) noexcept : mPtr{ptr} { }
  51. ~ComPtr() { if(mPtr) mPtr->Release(); }
  52. /* NOLINTNEXTLINE(bugprone-unhandled-self-assignment) Yes it is. */
  53. ComPtr& operator=(const ComPtr &rhs) noexcept(RefIsNoexcept)
  54. {
  55. if constexpr(RefIsNoexcept)
  56. {
  57. if(rhs.mPtr) rhs.mPtr->AddRef();
  58. if(mPtr) mPtr->Release();
  59. mPtr = rhs.mPtr;
  60. return *this;
  61. }
  62. else
  63. {
  64. ComPtr tmp{rhs};
  65. if(mPtr) mPtr->Release();
  66. mPtr = tmp.release();
  67. return *this;
  68. }
  69. }
  70. ComPtr& operator=(ComPtr&& rhs) noexcept(RefIsNoexcept)
  71. {
  72. if(&rhs != this)
  73. {
  74. if(mPtr) mPtr->Release();
  75. mPtr = std::exchange(rhs.mPtr, nullptr);
  76. }
  77. return *this;
  78. }
  79. void reset(T *ptr=nullptr) noexcept(RefIsNoexcept)
  80. {
  81. if(mPtr) mPtr->Release();
  82. mPtr = ptr;
  83. }
  84. explicit operator bool() const noexcept { return mPtr != nullptr; }
  85. T& operator*() const noexcept { return *mPtr; }
  86. T* operator->() const noexcept { return mPtr; }
  87. T* get() const noexcept { return mPtr; }
  88. T* release() noexcept { return std::exchange(mPtr, nullptr); }
  89. void swap(ComPtr &rhs) noexcept { std::swap(mPtr, rhs.mPtr); }
  90. void swap(ComPtr&& rhs) noexcept { std::swap(mPtr, rhs.mPtr); }
  91. private:
  92. T *mPtr{nullptr};
  93. };
  94. #endif