Created
June 10, 2023 00:27
-
-
Save wholivesinapineappleunderthesea/7b24cdec315275bf6bcd061417b6dff9 to your computer and use it in GitHub Desktop.
COMPtr implementnationn
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#pragma once | |
#include <Unknwn.h> | |
#include <exception> | |
template <typename T> struct COMPtrOut | |
{ | |
inline COMPtrOut() = delete; | |
inline COMPtrOut(const COMPtrOut&) = delete; | |
inline COMPtrOut(IUnknown** ptr) noexcept : m_pptr(ptr) | |
{ | |
} | |
inline operator T**() const noexcept | |
{ | |
return reinterpret_cast<T**>(m_pptr); | |
} | |
inline operator void**() const noexcept | |
{ | |
return reinterpret_cast<void**>(m_pptr); | |
} | |
private: | |
IUnknown** m_pptr{}; | |
}; | |
template <typename T> struct COMPtrInOut | |
{ | |
inline COMPtrInOut() = delete; | |
inline COMPtrInOut(const COMPtrInOut&) = delete; | |
inline COMPtrInOut(::IUnknown** ptr) noexcept | |
: m_pptr(ptr), m_previous(*ptr) | |
{ | |
} | |
inline ~COMPtrInOut() | |
{ | |
if (m_previous && m_previous != *m_pptr) | |
{ | |
m_previous->Release(); | |
} | |
} | |
inline operator T**() const noexcept | |
{ | |
return reinterpret_cast<T**>(m_pptr); | |
} | |
inline operator void**() const noexcept | |
{ | |
return reinterpret_cast<void**>(m_pptr); | |
} | |
private: | |
::IUnknown** m_pptr{}; | |
::IUnknown* m_previous{}; | |
}; | |
template <typename T> struct COMPtr | |
{ | |
static inline auto static_uuid = __uuidof(T); | |
using type = T; | |
using pointer = T*; | |
using reference = T&; | |
// Very similar to std::inout_ptr() | |
inline auto InOut() noexcept -> COMPtrInOut<T> | |
{ | |
return COMPtrInOut<T>{&_ptr}; | |
} | |
// Very similar to std::out_ptr() | |
inline auto Out() noexcept -> COMPtrOut<T> | |
{ | |
return COMPtrOut<T>{&_ptr}; | |
} | |
// Ptr operations: | |
inline auto operator->() noexcept -> pointer | |
{ | |
return Get(); | |
} | |
inline auto operator->() const noexcept -> const pointer | |
{ | |
return Get(); | |
} | |
inline auto operator*() noexcept -> reference | |
{ | |
return *Get(); | |
} | |
inline auto operator*() const noexcept -> const reference | |
{ | |
return *Get(); | |
} | |
inline operator pointer() noexcept | |
{ | |
return Get(); | |
} | |
inline operator const pointer() const noexcept | |
{ | |
return Get(); | |
} | |
// Boolean operations: | |
inline operator bool() const noexcept | |
{ | |
return Get() != nullptr; | |
} | |
inline auto operator!() const noexcept -> bool | |
{ | |
return Get() == nullptr; | |
} | |
inline auto operator==(std::nullptr_t) const noexcept -> bool | |
{ | |
return Get() == nullptr; | |
} | |
inline auto operator!=(std::nullptr_t) const noexcept -> bool | |
{ | |
return Get() != nullptr; | |
} | |
// Comparison operations: | |
template <template <class> class COMT, typename T2> | |
inline auto operator==(const COMT<T2>& other) const noexcept -> bool | |
requires std::equality_comparable_with<T*, T2*> | |
{ | |
return Get() == other.Get(); | |
} | |
template <template <class> class COMT, typename T2> | |
inline auto operator!=(const COMT<T2>& other) const noexcept -> bool | |
requires std::equality_comparable_with<T*, T2*> | |
{ | |
return Get() != other.Get(); | |
} | |
// Constructors: | |
inline COMPtr() noexcept : _ptr(nullptr) | |
{ | |
} | |
inline COMPtr(std::nullptr_t) noexcept : _ptr(nullptr) | |
{ | |
} | |
template <typename PtrT> | |
inline COMPtr(PtrT ptr) noexcept | |
requires std::derived_from<PtrT, T> | |
{ | |
_ptr = ptr; | |
} | |
inline COMPtr(::IUnknown* ptr) | |
{ | |
if (std::is_same_v<T, ::IUnknown>) | |
{ | |
_ptr = ptr; | |
} | |
else | |
{ | |
::IUnknown* ptemp{}; | |
const auto hr = ptr->QueryInterface( | |
static_uuid, reinterpret_cast<void**>(&ptemp)); | |
if (!SUCCEEDED(hr)) | |
{ | |
throw std::exception( | |
"QueryInterface failed, ptr will not be released!"); | |
} | |
_ptr = ptemp; | |
// MIGHT be different, but if not we still need to release | |
// (QueryInterface will AddRef) | |
ptr->Release(); | |
} | |
} | |
template <template <class> class COMT, typename T2> | |
inline COMPtr(const COMT<T2>& other) noexcept | |
requires std::convertible_to<T2*, T*> | |
{ | |
_ptr = other._ptr; | |
AddRef(); | |
} | |
template <template <class> class COMT, typename T2> | |
inline COMPtr(COMT<T2>&& other) noexcept | |
requires std::convertible_to<T2*, T*> | |
{ | |
_ptr = other._ptr; | |
other._ptr = nullptr; | |
} | |
// Destructor: | |
inline ~COMPtr() | |
{ | |
Reset(); | |
} | |
// Assignment operators: | |
inline auto operator=(std::nullptr_t) | |
{ | |
Reset(); | |
} | |
inline auto operator=(::IUnknown* ptr) | |
{ | |
if (std::is_same_v<T, ::IUnknown>) | |
{ | |
Reset(ptr); | |
} | |
else | |
{ | |
Reset(); | |
::IUnknown* ptemp{}; | |
const auto hr = ptr->QueryInterface( | |
static_uuid, reinterpret_cast<void**>(&ptemp)); | |
if (!SUCCEEDED(hr)) | |
{ | |
throw std::exception( | |
"QueryInterface failed, ptr will not be released!"); | |
} | |
_ptr = ptemp; | |
// MIGHT be different, but if not we still need to release | |
// (QueryInterface will AddRef) | |
ptr->Release(); | |
} | |
} | |
template <typename PtrT> | |
inline auto operator=(PtrT ptr) noexcept | |
requires (std::derived_from<PtrT, T> && !std::same_as<PtrT, ::IUnknown>) | |
{ | |
Reset(ptr); | |
} | |
template <template <class> class COMT, typename T2> | |
inline auto operator=(const COMT<T2>& other) noexcept | |
requires std::convertible_to<T2*, T*> | |
{ | |
Reset(other._ptr); | |
AddRef(); | |
} | |
template <template <class> class COMT, typename T2> | |
inline auto operator=(COMT<T2>&& other) noexcept | |
requires std::convertible_to<T2*, T*> | |
{ | |
Reset(other._ptr); | |
other._ptr = nullptr; | |
} | |
// Member functions: | |
inline auto Get() noexcept -> pointer | |
{ | |
return reinterpret_cast<pointer>(_ptr); | |
} | |
inline auto Get() const noexcept -> const pointer | |
{ | |
return reinterpret_cast<const pointer>(_ptr); | |
} | |
inline auto Reset(::IUnknown* ptr = nullptr) -> void | |
{ | |
Release(); | |
_ptr = ptr; | |
} | |
inline auto Release() -> void | |
{ | |
if (_ptr) | |
{ | |
_ptr->Release(); | |
_ptr = nullptr; | |
} | |
} | |
inline auto AddRef() -> void | |
{ | |
if (_ptr) | |
{ | |
_ptr->AddRef(); | |
} | |
} | |
::IUnknown* _ptr{}; | |
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
COMPtr<::IDXGISwapChain1> swapChain{}; | |
if (SUCCEEDED(m_dxgiFactory->CreateSwapChainForHwnd( | |
m_d3dCommandQueue.Get(), m_hwnd, | |
&swapChainDesc, nullptr, nullptr, swapChain.Out()))) | |
{ | |
... | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment