in strings/base_implements.h [749:1186]
struct __declspec(novtable) root_implements
: root_implements_composing_outer<std::disjunction_v<std::is_same<composing, I>...>>
, root_implements_composable_inner<D, std::disjunction_v<std::is_same<composable, I>...>>
, module_lock_updater<!std::disjunction_v<std::is_same<no_module_lock, I>...>>
{
using IInspectable = Windows::Foundation::IInspectable;
using root_implements_type = root_implements;
int32_t __stdcall QueryInterface(guid const& id, void** object) noexcept
{
if (this->outer())
{
return this->outer()->QueryInterface(id, object);
}
int32_t result = query_interface(id, object);
if (result == error_no_interface && this->m_inner)
{
result = static_cast<unknown_abi*>(get_abi(this->m_inner))->QueryInterface(id, object);
}
return result;
}
uint32_t __stdcall AddRef() noexcept
{
if (this->outer())
{
return this->outer()->AddRef();
}
return NonDelegatingAddRef();
}
uint32_t __stdcall Release() noexcept
{
if (this->outer())
{
return this->outer()->Release();
}
return NonDelegatingRelease();
}
struct abi_guard
{
abi_guard(D& derived) :
m_derived(derived)
{
m_derived.abi_enter();
}
~abi_guard()
{
m_derived.abi_exit();
}
private:
D& m_derived;
};
void abi_enter() const noexcept {}
void abi_exit() const noexcept {}
#if defined(_DEBUG) && !defined(WINRT_NO_MAKE_DETECTION)
// Please use winrt::make<T>(args...) to avoid allocating a C++/WinRT implementation type on the stack.
virtual void use_make_function_to_create_this_object() = 0;
#endif
protected:
virtual int32_t query_interface_tearoff(guid const&, void**) const noexcept
{
return error_no_interface;
}
root_implements() noexcept
{
}
virtual ~root_implements() noexcept
{
// If a weak reference is created during destruction, this ensures that it is also destroyed.
subtract_reference();
}
int32_t __stdcall GetIids(uint32_t* count, guid** array) noexcept
{
if (this->outer())
{
return this->outer()->GetIids(count, array);
}
return NonDelegatingGetIids(count, array);
}
int32_t __stdcall abi_GetRuntimeClassName(void** name) noexcept
{
if (this->outer())
{
return this->outer()->GetRuntimeClassName(name);
}
return NonDelegatingGetRuntimeClassName(name);
}
int32_t __stdcall abi_GetTrustLevel(Windows::Foundation::TrustLevel* trustLevel) noexcept
{
if (this->outer())
{
return this->outer()->GetTrustLevel(trustLevel);
}
return NonDelegatingGetTrustLevel(trustLevel);
}
uint32_t __stdcall NonDelegatingAddRef() noexcept
{
if constexpr (is_weak_ref_source::value)
{
uintptr_t count_or_pointer = m_references.load(std::memory_order_relaxed);
while (true)
{
if (is_weak_ref(count_or_pointer))
{
return decode_weak_ref(count_or_pointer)->increment_strong();
}
uintptr_t const target = count_or_pointer + 1;
if (m_references.compare_exchange_weak(count_or_pointer, target, std::memory_order_relaxed))
{
return static_cast<uint32_t>(target);
}
}
}
else
{
return 1 + m_references.fetch_add(1, std::memory_order_relaxed);
}
}
uint32_t __stdcall NonDelegatingRelease() noexcept
{
uint32_t const target = subtract_reference();
if (target == 0)
{
// If a weak reference was previously created, the m_references value will not be stable value (won't be zero).
// This ensures destruction has a stable value during destruction.
m_references = 1;
if constexpr (has_final_release::value)
{
D::final_release(std::unique_ptr<D>(static_cast<D*>(this)));
}
else
{
delete this;
}
}
return target;
}
int32_t __stdcall NonDelegatingQueryInterface(const guid& id, void** object) noexcept
{
if (is_guid_of<Windows::Foundation::IInspectable>(id) || is_guid_of<Windows::Foundation::IUnknown>(id))
{
auto result = to_abi<INonDelegatingInspectable>(this);
NonDelegatingAddRef();
*object = result;
return 0;
}
int32_t result = query_interface(id, object);
if (result == error_no_interface && this->m_inner)
{
result = static_cast<unknown_abi*>(get_abi(this->m_inner))->QueryInterface(id, object);
}
return result;
}
int32_t __stdcall NonDelegatingGetIids(uint32_t* count, guid** array) noexcept
{
const auto& local_iids = static_cast<D*>(this)->get_local_iids();
const uint32_t& local_count = local_iids.first;
if constexpr (root_implements_type::is_composing)
{
if (local_count > 0)
{
const com_array<guid>& inner_iids = get_interfaces(root_implements_type::m_inner);
*count = local_count + inner_iids.size();
*array = static_cast<guid*>(WINRT_IMPL_CoTaskMemAlloc(sizeof(guid)*(*count)));
if (*array == nullptr)
{
return error_bad_alloc;
}
*array = std::copy(local_iids.second, local_iids.second + local_count, *array);
std::copy(inner_iids.cbegin(), inner_iids.cend(), *array);
}
else
{
return static_cast<inspectable_abi*>(get_abi(root_implements_type::m_inner))->GetIids(count, array);
}
}
else
{
if (local_count > 0)
{
*count = local_count;
*array = static_cast<guid*>(WINRT_IMPL_CoTaskMemAlloc(sizeof(guid)*(*count)));
if (*array == nullptr)
{
return error_bad_alloc;
}
std::copy(local_iids.second, local_iids.second + local_count, *array);
}
else
{
*count = 0;
*array = nullptr;
}
}
return 0;
}
int32_t __stdcall NonDelegatingGetRuntimeClassName(void** name) noexcept try
{
*name = detach_abi(static_cast<D*>(this)->GetRuntimeClassName());
return 0;
}
catch (...) { return to_hresult(); }
int32_t __stdcall NonDelegatingGetTrustLevel(Windows::Foundation::TrustLevel* trustLevel) noexcept try
{
*trustLevel = static_cast<D*>(this)->GetTrustLevel();
return 0;
}
catch (...) { return to_hresult(); }
uint32_t subtract_reference() noexcept
{
if constexpr (is_weak_ref_source::value)
{
uintptr_t count_or_pointer = m_references.load(std::memory_order_relaxed);
while (true)
{
if (is_weak_ref(count_or_pointer))
{
return decode_weak_ref(count_or_pointer)->decrement_strong();
}
uintptr_t const target = count_or_pointer - 1;
if (m_references.compare_exchange_weak(count_or_pointer, target, std::memory_order_release, std::memory_order_relaxed))
{
return static_cast<uint32_t>(target);
}
}
}
else
{
return m_references.fetch_sub(1, std::memory_order_release) - 1;
}
}
template <typename T>
winrt::weak_ref<T> get_weak()
{
impl::IWeakReferenceSource* weak_ref = make_weak_ref();
if (!weak_ref)
{
throw std::bad_alloc{};
}
com_ptr<impl::IWeakReferenceSource> source;
attach_abi(source, weak_ref);
winrt::weak_ref<T> result;
check_hresult(source->GetWeakReference(result.put()));
return result;
}
virtual Windows::Foundation::TrustLevel GetTrustLevel() const noexcept
{
return Windows::Foundation::TrustLevel::BaseTrust;
}
private:
class has_final_release
{
template <typename U, typename = decltype(std::declval<U>().final_release(0))> static constexpr bool get_value(int) { return true; }
template <typename> static constexpr bool get_value(...) { return false; }
public:
static constexpr bool value = get_value<D>(0);
};
using is_agile = std::negation<std::disjunction<std::is_same<non_agile, I>...>>;
using is_inspectable = std::disjunction<std::is_base_of<Windows::Foundation::IInspectable, I>...>;
using is_weak_ref_source = std::conjunction<is_inspectable, std::negation<std::disjunction<std::is_same<no_weak_ref, I>...>>>;
using use_module_lock = std::negation<std::disjunction<std::is_same<no_module_lock, I>...>>;
using weak_ref_t = impl::weak_ref<is_agile::value, use_module_lock::value>;
std::atomic<std::conditional_t<is_weak_ref_source::value, uintptr_t, uint32_t>> m_references{ 1 };
int32_t query_interface(guid const& id, void** object) noexcept
{
*object = static_cast<D*>(this)->find_interface(id);
if (*object != nullptr)
{
AddRef();
return 0;
}
if constexpr (is_agile::value)
{
if (is_guid_of<IAgileObject>(id))
{
*object = get_unknown();
AddRef();
return 0;
}
if (is_guid_of<IMarshal>(id))
{
return make_marshaler(get_unknown(), object);
}
}
if constexpr (is_inspectable::value)
{
if (is_guid_of<Windows::Foundation::IInspectable>(id))
{
*object = find_inspectable();
AddRef();
return 0;
}
}
if (is_guid_of<Windows::Foundation::IUnknown>(id))
{
*object = get_unknown();
AddRef();
return 0;
}
if constexpr (is_weak_ref_source::value)
{
if (is_guid_of<impl::IWeakReferenceSource>(id))
{
*object = make_weak_ref();
return *object ? error_ok : error_bad_alloc;
}
}
return query_interface_tearoff(id, object);
}
impl::IWeakReferenceSource* make_weak_ref() noexcept
{
static_assert(is_weak_ref_source::value, "This is only for weak ref support.");
uintptr_t count_or_pointer = m_references.load(std::memory_order_relaxed);
if (is_weak_ref(count_or_pointer))
{
return decode_weak_ref(count_or_pointer)->get_source();
}
com_ptr<weak_ref_t> weak_ref;
*weak_ref.put() = new (std::nothrow) weak_ref_t(get_unknown(), static_cast<uint32_t>(count_or_pointer));
if (!weak_ref)
{
return nullptr;
}
uintptr_t const encoding = encode_weak_ref(weak_ref.get());
for (;;)
{
if (m_references.compare_exchange_weak(count_or_pointer, encoding, std::memory_order_acq_rel, std::memory_order_relaxed))
{
impl::IWeakReferenceSource* result = weak_ref->get_source();
detach_abi(weak_ref);
return result;
}
if (is_weak_ref(count_or_pointer))
{
return decode_weak_ref(count_or_pointer)->get_source();
}
weak_ref->set_strong(static_cast<uint32_t>(count_or_pointer));
}
}
static bool is_weak_ref(intptr_t const value) noexcept
{
static_assert(is_weak_ref_source::value, "This is only for weak ref support.");
return value < 0;
}
static weak_ref_t* decode_weak_ref(uintptr_t const value) noexcept
{
static_assert(is_weak_ref_source::value, "This is only for weak ref support.");
return reinterpret_cast<weak_ref_t*>(value << 1);
}
static uintptr_t encode_weak_ref(weak_ref_t* value) noexcept
{
static_assert(is_weak_ref_source::value, "This is only for weak ref support.");
constexpr uintptr_t pointer_flag = static_cast<uintptr_t>(1) << ((sizeof(uintptr_t) * 8) - 1);
WINRT_ASSERT((reinterpret_cast<uintptr_t>(value) & 1) == 0);
return (reinterpret_cast<uintptr_t>(value) >> 1) | pointer_flag;
}
virtual unknown_abi* get_unknown() const noexcept = 0;
virtual std::pair<uint32_t, const guid*> get_local_iids() const noexcept = 0;
virtual hstring GetRuntimeClassName() const = 0;
virtual void* find_interface(guid const&) const noexcept = 0;
virtual inspectable_abi* find_inspectable() const noexcept = 0;
template <typename, typename, typename>
friend struct impl::produce_base;
template <typename, typename>
friend struct impl::produce;
};