//********************************************************* // // Copyright (c) Microsoft. All rights reserved. // This code is licensed under the MIT License. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF // ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED // TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A // PARTICULAR PURPOSE AND NONINFRINGEMENT. // //********************************************************* //! @file //! Various types and functions for working with the Windows Runtime #ifndef __WIL_WINRT_INCLUDED #define __WIL_WINRT_INCLUDED #include #include #include #include #include #include "result.h" #include "com.h" #include "resource.h" #include #include #ifdef __cplusplus_winrt #include // bring in the CRT iterator for support for C++ CX code #endif /// @cond #if defined(WIL_ENABLE_EXCEPTIONS) && !defined(__WI_HAS_STD_LESS) #ifdef __has_include #if __has_include() #define __WI_HAS_STD_LESS 1 #include #endif // Otherwise, not using STL; don't specialize std::less #else // Fall back to the old way of forward declaring std::less #define __WI_HAS_STD_LESS 1 #pragma warning(push) #pragma warning(disable : 4643) // Forward declaring '...' in namespace std is not permitted by the C++ Standard. namespace std { template struct less; } #pragma warning(pop) #endif #endif #if defined(WIL_ENABLE_EXCEPTIONS) && defined(__has_include) #if __has_include() #define __WI_HAS_STD_VECTOR 1 #include #endif #endif /// @endcond // This enables this code to be used in code that uses the ABI prefix or not. // Code using the public SDK and C++ CX code has the ABI prefix, windows internal // is built in a way that does not. /// @cond #if !defined(MIDL_NS_PREFIX) && !defined(____x_ABI_CWindows_CFoundation_CIClosable_FWD_DEFINED__) // Internal .idl files use the namespace without the ABI prefix. Macro out ABI for that case #pragma push_macro("ABI") #undef ABI #define ABI #endif /// @endcond namespace wil { // time_t is the number of 1 - second intervals since January 1, 1970. constexpr long long SecondsToStartOf1970 = 0x2b6109100; constexpr long long HundredNanoSecondsInSecond = 10000000LL; inline __time64_t DateTime_to_time_t(ABI::Windows::Foundation::DateTime dateTime) { // DateTime is the number of 100 - nanosecond intervals since January 1, 1601. return (dateTime.UniversalTime / HundredNanoSecondsInSecond - SecondsToStartOf1970); } inline ABI::Windows::Foundation::DateTime time_t_to_DateTime(__time64_t timeT) { ABI::Windows::Foundation::DateTime dateTime; dateTime.UniversalTime = (timeT + SecondsToStartOf1970) * HundredNanoSecondsInSecond; return dateTime; } #pragma region HSTRING Helpers /// @cond namespace details { // hstring_compare is used to assist in HSTRING comparison of two potentially non-similar string types. E.g. // comparing a raw HSTRING with WRL's HString/HStringReference/etc. The consumer can optionally inhibit the // deduction of array sizes by providing 'true' for the 'InhibitStringArrays' template argument. This is // generally done in scenarios where the consumer cannot guarantee that the input argument types are perfectly // preserved from end-to-end. E.g. if a single function in the execution path captures an array as const T&, // then it is impossible to differentiate const arrays (where we generally do want to deduce length) from // non-const arrays (where we generally do not want to deduce length). The consumer can also optionally choose // to perform case-insensitive comparison by providing 'true' for the 'IgnoreCase' template argument. template struct hstring_compare { // get_buffer returns the string buffer and length for the supported string types static const wchar_t* get_buffer(HSTRING hstr, UINT32* length) WI_NOEXCEPT { return ::WindowsGetStringRawBuffer(hstr, length); } static const wchar_t* get_buffer(const Microsoft::WRL::Wrappers::HString& hstr, UINT32* length) WI_NOEXCEPT { return hstr.GetRawBuffer(length); } static const wchar_t* get_buffer(const Microsoft::WRL::Wrappers::HStringReference& hstr, UINT32* length) WI_NOEXCEPT { return hstr.GetRawBuffer(length); } static const wchar_t* get_buffer(const unique_hstring& str, UINT32* length) WI_NOEXCEPT { return ::WindowsGetStringRawBuffer(str.get(), length); } template static wistd::enable_if_t get_buffer(const wchar_t* str, UINT32* length) WI_NOEXCEPT { str = (str != nullptr) ? str : L""; *length = static_cast(wcslen(str)); return str; } template static wistd::enable_if_t< wistd::conjunction, wistd::is_same>, wchar_t>, wistd::bool_constant>::value, const wchar_t*> get_buffer(StringT str, UINT32* length) WI_NOEXCEPT { str = (str != nullptr) ? str : L""; *length = static_cast(wcslen(str)); return str; } template static wistd::enable_if_t get_buffer(const wchar_t (&str)[Size], UINT32* length) WI_NOEXCEPT { *length = Size - 1; return str; } template static wistd::enable_if_t get_buffer(wchar_t (&str)[Size], UINT32* length) WI_NOEXCEPT { *length = static_cast(wcslen(str)); return str; } // Overload for std::wstring, or at least things that behave like std::wstring, without adding a dependency // on STL headers template static wistd::enable_if_t< wistd::conjunction_v< wistd::is_constructible, wistd::is_convertible().data()), const wchar_t*>, wistd::is_same().size())>>, const wchar_t*> get_buffer(const StringT& str, UINT32* length) WI_NOEXCEPT { *length = static_cast(str.size()); const wchar_t* ret = str.data(); return ret ? ret : L""; } template static auto compare(LhsT&& lhs, RhsT&& rhs) -> decltype(get_buffer(lhs, wistd::declval()), get_buffer(rhs, wistd::declval()), int()) { UINT32 lhsLength; UINT32 rhsLength; auto lhsBuffer = get_buffer(wistd::forward(lhs), &lhsLength); auto rhsBuffer = get_buffer(wistd::forward(rhs), &rhsLength); const auto result = ::CompareStringOrdinal(lhsBuffer, lhsLength, rhsBuffer, rhsLength, IgnoreCase ? TRUE : FALSE); WI_ASSERT(result != 0); return result; } template static auto equals(LhsT&& lhs, RhsT&& rhs) WI_NOEXCEPT->decltype(compare(wistd::forward(lhs), wistd::forward(rhs)), bool()) { return compare(wistd::forward(lhs), wistd::forward(rhs)) == CSTR_EQUAL; } template static auto not_equals(LhsT&& lhs, RhsT&& rhs) WI_NOEXCEPT->decltype(compare(wistd::forward(lhs), wistd::forward(rhs)), bool()) { return compare(wistd::forward(lhs), wistd::forward(rhs)) != CSTR_EQUAL; } template static auto less(LhsT&& lhs, RhsT&& rhs) WI_NOEXCEPT->decltype(compare(wistd::forward(lhs), wistd::forward(rhs)), bool()) { return compare(wistd::forward(lhs), wistd::forward(rhs)) == CSTR_LESS_THAN; } template static auto less_equals(LhsT&& lhs, RhsT&& rhs) WI_NOEXCEPT->decltype(compare(wistd::forward(lhs), wistd::forward(rhs)), bool()) { return compare(wistd::forward(lhs), wistd::forward(rhs)) != CSTR_GREATER_THAN; } template static auto greater(LhsT&& lhs, RhsT&& rhs) WI_NOEXCEPT->decltype(compare(wistd::forward(lhs), wistd::forward(rhs)), bool()) { return compare(wistd::forward(lhs), wistd::forward(rhs)) == CSTR_GREATER_THAN; } template static auto greater_equals(LhsT&& lhs, RhsT&& rhs) WI_NOEXCEPT->decltype(compare(wistd::forward(lhs), wistd::forward(rhs)), bool()) { return compare(wistd::forward(lhs), wistd::forward(rhs)) != CSTR_LESS_THAN; } }; } // namespace details /// @endcond //! Detects if one or more embedded null is present in an HSTRING. inline bool HasEmbeddedNull(_In_opt_ HSTRING value) { BOOL hasEmbeddedNull = FALSE; (void)WindowsStringHasEmbeddedNull(value, &hasEmbeddedNull); return hasEmbeddedNull != FALSE; } /** TwoPhaseHStringConstructor help using the 2 phase constructor pattern for HSTRINGs. @code auto stringConstructor = wil::TwoPhaseHStringConstructor::Preallocate(size); RETURN_IF_NULL_ALLOC(stringConstructor.Get()); RETURN_IF_FAILED(stream->Read(stringConstructor.Get(), stringConstructor.ByteSize(), &bytesRead)); // Validate stream contents, sizes must match, string must be null terminated. RETURN_IF_FAILED(stringConstructor.Validate(bytesRead)); wil::unique_hstring string { stringConstructor.Promote() }; @endcode See also wil::unique_hstring_buffer. */ struct TwoPhaseHStringConstructor { TwoPhaseHStringConstructor() = delete; TwoPhaseHStringConstructor(const TwoPhaseHStringConstructor&) = delete; void operator=(const TwoPhaseHStringConstructor&) = delete; TwoPhaseHStringConstructor(TwoPhaseHStringConstructor&& other) WI_NOEXCEPT { m_characterLength = other.m_characterLength; other.m_characterLength = 0; m_maker = wistd::move(other.m_maker); } static TwoPhaseHStringConstructor Preallocate(UINT32 characterLength) { return TwoPhaseHStringConstructor{characterLength}; } //! Returns the HSTRING after it has been populated like Detatch() or release(); be sure to put this in a RAII type to manage //! its lifetime. HSTRING Promote() { m_characterLength = 0; return m_maker.release().release(); } ~TwoPhaseHStringConstructor() = default; WI_NODISCARD explicit operator PCWSTR() const { // This is set by WindowsPromoteStringBuffer() which must be called to // construct this object via the static method Preallocate(). return m_maker.buffer(); } //! Returns a pointer for the buffer so it can be populated WI_NODISCARD wchar_t* Get() const { return const_cast(m_maker.buffer()); } //! Used to validate range of buffer when populating. WI_NODISCARD ULONG ByteSize() const { return m_characterLength * sizeof(wchar_t); } /** Ensure that the size of the data provided is consistent with the pre-allocated buffer. It seems that WindowsPreallocateStringBuffer() provides the null terminator in the buffer (based on testing) so this can be called before populating the buffer. */ WI_NODISCARD HRESULT Validate(ULONG bytesRead) const { // Null termination is required for the buffer before calling WindowsPromoteStringBuffer(). RETURN_HR_IF(HRESULT_FROM_WIN32(ERROR_INVALID_DATA), (bytesRead != ByteSize()) || (Get()[m_characterLength] != L'\0')); return S_OK; } private: TwoPhaseHStringConstructor(UINT32 characterLength) : m_characterLength(characterLength) { (void)m_maker.make(nullptr, characterLength); } UINT32 m_characterLength; details::string_maker m_maker; }; //! A transparent less-than comparison function object that enables comparison of various string types intended for //! use with associative containers (such as `std::set`, `std::map`, etc.) that use //! `Microsoft::WRL::Wrappers::HString` as the key type. This removes the need for the consumer to explicitly //! create an `HString` object when using lookup functions such as `find`, `lower_bound`, etc. For example, the //! following scenarios would all work exactly as you would expect them to: //! ~~~ //! std::map map; //! const wchar_t constArray[] = L"foo"; //! wchar_t nonConstArray[MAX_PATH] = L"foo"; //! //! HString key; //! THROW_IF_FAILED(key.Set(constArray)); //! map.emplace(std::move(key), 42); //! //! HString str; //! wil::unique_hstring uniqueStr; //! THROW_IF_FAILED(str.Set(L"foo")); //! THROW_IF_FAILED(str.CopyTo(&uniqueStr)); //! //! // All of the following return an iterator to the pair { L"foo", 42 } //! map.find(str); //! map.find(str.Get()); //! map.find(HStringReference(constArray)); //! map.find(uniqueStr); //! map.find(std::wstring(constArray)); //! map.find(constArray); //! map.find(nonConstArray); //! map.find(static_cast(constArray)); //! ~~~ //! The first four calls in the example above use `WindowsGetStringRawBuffer` (or equivalent) to get the string //! buffer and length for the comparison. The fifth example uses `std::wstring::c_str` and `std::wstring::length` //! for getting these two values. The remaining three examples use only the string buffer and call `wcslen` for the //! length. That is, the length is *not* deduced for either array. This is because argument types are not always //! perfectly preserved by container functions and in fact are often captured as const references making it //! impossible to differentiate const arrays - where we can safely deduce length - from non const arrays - where we //! cannot safely deduce length since the buffer may be larger than actually needed (e.g. creating a //! `char[MAX_PATH]` array, but only filling it with 10 characters). The implications of this behavior is that //! string literals that contain embedded null characters will only include the part of the buffer up to the first //! null character. For example, the following example will result in all calls to `find` returning an end //! iterator. //! ~~~ //! std::map map; //! const wchar_t constArray[] = L"foo\0bar"; //! wchar_t nonConstArray[MAX_PATH] = L"foo\0bar"; //! //! // Create the key with the embedded null character //! HString key; //! THROW_IF_FAILED(key.Set(constArray)); //! map.emplace(std::move(key), 42); //! //! // All of the following return map.end() since they look for the string "foo" //! map.find(constArray); //! map.find(nonConstArray); //! map.find(static_cast(constArray)); //! ~~~ //! In order to search using a string literal that contains embedded null characters, a simple alternative is to //! first create an `HStringReference` and use that for the function call: //! ~~~ //! // HStringReference's constructor *will* deduce the length of const arrays //! map.find(HStringReference(constArray)); //! ~~~ struct hstring_less { using is_transparent = void; template WI_NODISCARD auto operator()(const LhsT& lhs, const RhsT& rhs) const WI_NOEXCEPT->decltype(details::hstring_compare::less(lhs, rhs)) { return details::hstring_compare::less(lhs, rhs); } }; //! A transparent less-than comparison function object whose behavior is equivalent to that of @ref hstring_less //! with the one difference that comparisons are case-insensitive. That is, the following example will correctly //! find the inserted value: //! ~~~ //! std::map map; //! //! HString key; //! THROW_IF_FAILED(key.Set(L"foo")); //! map.emplace(std::move(key), 42); //! //! // All of the following return an iterator to the pair { L"foo", 42 } //! map.find(L"FOo"); //! map.find(HStringReference(L"fOo")); //! map.find(HStringReference(L"fOO").Get()); //! ~~~ struct hstring_insensitive_less { using is_transparent = void; template WI_NODISCARD auto operator()(const LhsT& lhs, const RhsT& rhs) const WI_NOEXCEPT->decltype(details::hstring_compare::less(lhs, rhs)) { return details::hstring_compare::less(lhs, rhs); } }; #pragma endregion /// @cond namespace details { // MapToSmartType::type is used to map a raw type into an RAII expression // of it. This is needed when lifetime management of the type is needed, for example // when holding them as a value produced in an iterator. // This type has a common set of methods used to abstract the access to the value // that is similar to ComPtr<> and the WRL Wrappers: Get(), GetAddressOf() and other operators. // Clients of the smart type must use those to access the value. // TODO: Having the base definition defined will result in creating leaks if a type // that needs resource management (e.g. PROPVARIANT) that has not specialized is used. // // One fix is to use std::is_enum to cover that case and leave the base definition undefined. // That base should use static_assert to inform clients how to fix the lack of specialization. template struct MapToSmartType { #pragma warning(push) #pragma warning(disable : 4702) // https://github.com/Microsoft/wil/issues/2 struct type // T holder { type() = default; type(T&& value) : m_value(wistd::forward(value)) { } WI_NODISCARD operator T() const { return m_value; } type& operator=(T&& value) { m_value = wistd::forward(value); return *this; } WI_NODISCARD T Get() const { return m_value; } // Returning T&& to support move only types // In case of absence of T::operator=(T&&) a call to T::operator=(const T&) will happen T&& Get() { return wistd::move(m_value); } WI_NODISCARD HRESULT CopyTo(T* result) const { *result = m_value; return S_OK; } T* GetAddressOf() { return &m_value; } T* ReleaseAndGetAddressOf() { return &m_value; } T* operator&() { return &m_value; } T m_value{}; }; #pragma warning(pop) }; // IUnknown * derived -> Microsoft::WRL::ComPtr<> template struct MapToSmartType::type>::value>::type> { typedef Microsoft::WRL::ComPtr::type> type; }; // HSTRING -> Microsoft::WRL::Wrappers::HString template <> struct MapToSmartType { class HStringWithRelease : public Microsoft::WRL::Wrappers::HString { public: // Unlike all other WRL types HString does not have ReleaseAndGetAddressOf and // GetAddressOf() has non-standard behavior, calling Release(). HSTRING* ReleaseAndGetAddressOf() WI_NOEXCEPT { Release(); return &hstr_; } }; typedef HStringWithRelease type; }; // WinRT interfaces like IVector<>, IAsyncOperation<> and IIterable<> can be templated // on a runtime class (instead of an interface or primitive type). In these cases the objects // produced by those interfaces implement an interface defined by the runtime class default interface. // // These templates deduce the type of the produced interface or pass through // the type unmodified in the non runtime class case. // // for example: // IAsyncOperation -> IAsyncOperation // For IVector, IVectorView. template struct MapVectorResultType { template static TResult PeekGetAtType(HRESULT (STDMETHODCALLTYPE TVector::*)(unsigned, TResult*)); typedef decltype(PeekGetAtType(&VectorType::GetAt)) type; }; // For IIterator. template struct MapIteratorResultType { template static TResult PeekCurrentType(HRESULT (STDMETHODCALLTYPE TIterable::*)(TResult*)); typedef decltype(PeekCurrentType(&ABI::Windows::Foundation::Collections::IIterator::get_Current)) type; }; // For IAsyncOperation. template struct MapAsyncOpResultType { template static TResult PeekGetResultsType(HRESULT (STDMETHODCALLTYPE TAsyncOperation::*)(TResult*)); typedef decltype(PeekGetResultsType(&ABI::Windows::Foundation::IAsyncOperation::GetResults)) type; }; // For IAsyncOperationWithProgress. template struct MapAsyncOpProgressResultType { template static TResult PeekGetResultsType(HRESULT (STDMETHODCALLTYPE TAsyncOperation::*)(TResult*)); typedef decltype(PeekGetResultsType(&ABI::Windows::Foundation::IAsyncOperationWithProgress::GetResults)) type; }; // No support for IAsyncActionWithProgress

none of these (currently) use // a runtime class for the progress type. } // namespace details /// @endcond #pragma region C++ iterators for WinRT collections for use with range based for and STL algorithms /** Range base for and STL algorithms support for WinRT ABI collection types, IVector, IVectorView, IIterable similar to support provided by for C++ CX. Three error handling policies are supported. @code ComPtr collection = GetCollection(); // can be IVector, IVectorView or IIterable for (auto const& element : wil::get_range(collection.Get())) // exceptions for (auto const& element : wil::get_range_nothrow(collection.Get(), &hr)) // error code for (auto const& element : wil::get_range_failfast(collection.Get())) // fail fast { // use element } @endcode Standard algorithm example: @code ComPtr> files = GetFiles(); auto fileRange = wil::get_range_nothrow(files.Get()); auto itFound = std::find_if(fileRange.begin(), fileRange.end(), [](ComPtr file) -> bool { return true; // first element in range }); @endcode */ #pragma region exception and fail fast based IVector<>/IVectorView<> template class vector_range { public: typedef typename details::MapVectorResultType::type TResult; typedef typename details::MapToSmartType::type TSmart; vector_range() = delete; explicit vector_range(_In_ VectorType* vector) : m_v(vector) { } class vector_iterator { public: #if defined(_XUTILITY_) || defined(WIL_DOXYGEN) // could be random_access_iterator_tag but missing some features typedef ::std::bidirectional_iterator_tag iterator_category; #endif typedef TSmart value_type; typedef ptrdiff_t difference_type; typedef const TSmart* pointer; typedef const TSmart& reference; // for begin() vector_iterator(VectorType* v, unsigned int pos) : m_v(v), m_i(pos) { } // for end() vector_iterator() : m_v(nullptr), m_i(-1) { } vector_iterator(const vector_iterator& other) { m_v = other.m_v; m_i = other.m_i; err_policy::HResult(other.m_element.CopyTo(m_element.GetAddressOf())); } vector_iterator& operator=(const vector_iterator& other) { if (this != wistd::addressof(other)) { m_v = other.m_v; m_i = other.m_i; err_policy::HResult(other.m_element.CopyTo(m_element.ReleaseAndGetAddressOf())); } return *this; } reference operator*() { err_policy::HResult(m_v->GetAt(m_i, m_element.ReleaseAndGetAddressOf())); return m_element; } pointer operator->() { err_policy::HResult(m_v->GetAt(m_i, m_element.ReleaseAndGetAddressOf())); return wistd::addressof(m_element); } vector_iterator& operator++() { ++m_i; return *this; } vector_iterator& operator--() { --m_i; return *this; } vector_iterator operator++(int) { vector_iterator old(*this); ++*this; return old; } vector_iterator operator--(int) { vector_iterator old(*this); --*this; return old; } vector_iterator& operator+=(int n) { m_i += n; return *this; } vector_iterator& operator-=(int n) { m_i -= n; return *this; } WI_NODISCARD vector_iterator operator+(int n) const { vector_iterator ret(*this); ret += n; return ret; } WI_NODISCARD vector_iterator operator-(int n) const { vector_iterator ret(*this); ret -= n; return ret; } WI_NODISCARD ptrdiff_t operator-(const vector_iterator& other) const { return m_i - other.m_i; } WI_NODISCARD bool operator==(const vector_iterator& other) const { return m_i == other.m_i; } WI_NODISCARD bool operator!=(const vector_iterator& other) const { return m_i != other.m_i; } WI_NODISCARD bool operator<(const vector_iterator& other) const { return m_i < other.m_i; } WI_NODISCARD bool operator>(const vector_iterator& other) const { return m_i > other.m_i; } WI_NODISCARD bool operator<=(const vector_iterator& other) const { return m_i <= other.m_i; } WI_NODISCARD bool operator>=(const vector_iterator& other) const { return m_i >= other.m_i; } private: VectorType* m_v; // weak, collection must outlive iterators. unsigned int m_i; TSmart m_element; }; vector_iterator begin() { return vector_iterator(m_v, 0); } vector_iterator end() { unsigned int size; err_policy::HResult(m_v->get_Size(&size)); return vector_iterator(m_v, size); } private: VectorType* m_v; // weak, collection must outlive iterators. }; #pragma endregion #pragma region error code based IVector<>/IVectorView<> __WI_ITR_NAMESPACE_BEGIN template class vector_range_nothrow { public: typedef typename details::MapVectorResultType::type TResult; typedef typename details::MapToSmartType::type TSmart; vector_range_nothrow() = delete; vector_range_nothrow(const vector_range_nothrow&) = delete; vector_range_nothrow& operator=(const vector_range_nothrow&) = delete; vector_range_nothrow(vector_range_nothrow&& other) WI_NOEXCEPT : m_v(other.m_v), m_size(other.m_size), m_result(other.m_result), m_resultStorage(other.m_resultStorage), m_currentElement(wistd::move(other.m_currentElement)) { } vector_range_nothrow(_In_ VectorType* vector, HRESULT* result = nullptr) : m_v(vector), m_result(result ? result : &m_resultStorage) { *m_result = m_v->get_Size(&m_size); } class vector_iterator_nothrow { public: #if defined(_XUTILITY_) || defined(WIL_DOXYGEN) // must be input_iterator_tag as use (via ++, --, etc.) of one invalidates the other. typedef ::std::input_iterator_tag iterator_category; #endif typedef TSmart value_type; typedef ptrdiff_t difference_type; typedef const TSmart* pointer; typedef const TSmart& reference; vector_iterator_nothrow() = delete; vector_iterator_nothrow(vector_range_nothrow* range, unsigned int pos) : m_range(range), m_i(pos) #if WIL_ITERATOR_DEBUG_LEVEL > 0 , m_version(range->m_version) #endif { } WI_NODISCARD reference operator*() const { return *this->operator->(); } WI_NODISCARD pointer operator->() const { #if WIL_ITERATOR_DEBUG_LEVEL > 0 WI_FAIL_FAST_ASSERT_MSG(m_version == m_range->m_version, "Dereferencing an out-of-date vector_iterator_nothrow"); WI_FAIL_FAST_ASSERT_MSG(SUCCEEDED(*m_range->m_result), "Dereferencing a vector_iterator_nothrow in a failed state"); WI_FAIL_FAST_ASSERT_MSG(m_i < m_range->m_size, "Dereferencing an 'end' iterator"); #endif return wistd::addressof(m_range->m_currentElement); } vector_iterator_nothrow& operator++() { return *this += 1; } vector_iterator_nothrow& operator--() { return *this += -1; } vector_iterator_nothrow operator++(int) { vector_iterator_nothrow old(*this); ++*this; return old; } vector_iterator_nothrow operator--(int) { vector_iterator_nothrow old(*this); --*this; return old; } vector_iterator_nothrow& operator+=(int n) { #if WIL_ITERATOR_DEBUG_LEVEL == 2 // This is _technically_ safe because we are not reading the out-of-date cached value, however having two active // copies of iterators is generally a sign of problematic code with a bug waiting to happen WI_FAIL_FAST_ASSERT_MSG( m_version == m_range->m_version, "Incrementing/decrementing an out-of-date copy of a vector_iterator_nothrow"); #endif m_i += n; #if WIL_ITERATOR_DEBUG_LEVEL > 0 // NOTE: 'm_i' is unsigned, hence the single check for increment/decrement WI_FAIL_FAST_ASSERT_MSG(m_i <= m_range->m_size, "Incrementing/decrementing a vector_iterator_nothrow out of range"); #endif m_range->get_at_current(m_i); #if WIL_ITERATOR_DEBUG_LEVEL > 0 m_version = m_range->m_version; #endif return *this; } vector_iterator_nothrow& operator-=(int n) { return *this += -n; } WI_NODISCARD bool operator==(vector_iterator_nothrow const& other) const { return FAILED(*m_range->m_result) || (m_i == other.m_i); } WI_NODISCARD bool operator!=(vector_iterator_nothrow const& other) const { return !operator==(other); } private: vector_range_nothrow* m_range; unsigned int m_i = 0; #if WIL_ITERATOR_DEBUG_LEVEL > 0 // For checked iterator support; must match the version in 'm_range' int m_version = 0; #endif }; vector_iterator_nothrow begin() { // NOTE: Calling 'begin()' more than once is explicitly allowed as a way to reset the range, however because state is // shared between all iterators, this invalidates previously created iterators get_at_current(0); return vector_iterator_nothrow(this, 0); } vector_iterator_nothrow end() { return vector_iterator_nothrow(this, m_size); } // Note, the error code is observed in operator!= and operator==, it always // returns "equal" in the failed state to force the compare to the end // iterator to return false and stop the loop. // // Is this ok for the general case? void get_at_current(unsigned int i) { if (SUCCEEDED(*m_result) && (i < m_size)) { *m_result = m_v->GetAt(i, m_currentElement.ReleaseAndGetAddressOf()); #if WIL_ITERATOR_DEBUG_LEVEL > 0 ++m_version; #endif } } private: VectorType* m_v; // weak, collection must outlive iterators. unsigned int m_size; // This state is shared by vector_iterator_nothrow instances. this means // use of one iterator invalidates the other. HRESULT* m_result; HRESULT m_resultStorage = S_OK; // for the case where the caller does not provide the location to store the result TSmart m_currentElement; #if WIL_ITERATOR_DEBUG_LEVEL > 0 // For checked iterator support int m_version = 0; #endif }; __WI_ITR_NAMESPACE_END #pragma endregion #pragma region exception and fail fast based IIterable<> template class iterable_range { public: typedef typename details::MapIteratorResultType::type TResult; typedef typename details::MapToSmartType::type TSmart; explicit iterable_range(_In_ ABI::Windows::Foundation::Collections::IIterable* iterable) : m_iterable(iterable) { } class iterable_iterator { public: #if defined(_XUTILITY_) || defined(WIL_DOXYGEN) typedef ::std::forward_iterator_tag iterator_category; #endif typedef TSmart value_type; typedef ptrdiff_t difference_type; typedef const TSmart* pointer; typedef const TSmart& reference; iterable_iterator() : m_i(-1) { } // for begin() explicit iterable_iterator(_In_ ABI::Windows::Foundation::Collections::IIterable* iterable) { err_policy::HResult(iterable->First(&m_iterator)); boolean hasCurrent; err_policy::HResult(m_iterator->get_HasCurrent(&hasCurrent)); m_i = hasCurrent ? 0 : -1; } // for end() iterable_iterator(int /*currentIndex*/) : m_i(-1) { } iterable_iterator(const iterable_iterator& other) { m_iterator = other.m_iterator; m_i = other.m_i; err_policy::HResult(other.m_element.CopyTo(m_element.GetAddressOf())); } iterable_iterator& operator=(const iterable_iterator& other) { if (this != wistd::addressof(other)) { m_iterator = other.m_iterator; m_i = other.m_i; err_policy::HResult(other.m_element.CopyTo(m_element.ReleaseAndGetAddressOf())); } return *this; } WI_NODISCARD bool operator==(iterable_iterator const& other) const { return m_i == other.m_i; } WI_NODISCARD bool operator!=(iterable_iterator const& other) const { return !operator==(other); } reference operator*() { err_policy::HResult(m_iterator->get_Current(m_element.ReleaseAndGetAddressOf())); return m_element; } pointer operator->() { err_policy::HResult(m_iterator->get_Current(m_element.ReleaseAndGetAddressOf())); return wistd::addressof(m_element); } iterable_iterator& operator++() { boolean hasCurrent; err_policy::HResult(m_iterator->MoveNext(&hasCurrent)); if (hasCurrent) { m_i++; } else { m_i = -1; } return *this; } iterable_iterator operator++(int) { iterable_iterator old(*this); ++*this; return old; } private: Microsoft::WRL::ComPtr> m_iterator; int m_i; TSmart m_element; }; iterable_iterator begin() { return iterable_iterator(m_iterable); } iterable_iterator end() { return iterable_iterator(); } private: // weak, collection must outlive iterators. ABI::Windows::Foundation::Collections::IIterable* m_iterable; }; #pragma endregion #if defined(__WI_HAS_STD_VECTOR) || defined(WIL_DOXYGEN) /** Converts WinRT vectors to std::vector by requesting the collection's data in a single operation. This can be more efficient in terms of IPC cost than iteratively processing it. @code ComPtr> values = GetValues(); std::vector> allData = wil::to_vector(values); for (ComPtr const& item : allData) { // use item } @endcode Can be used for ABI::Windows::Foundation::Collections::IVector and ABI::Windows::Foundation::Collections::IVectorView */ template auto to_vector(VectorType* src) { using TResult = typename details::MapVectorResultType::type; using TSmart = typename details::MapToSmartType::type; static_assert(sizeof(TResult) == sizeof(TSmart), "result and smart sizes are different"); std::vector output; UINT32 expected = 0; THROW_IF_FAILED(src->get_Size(&expected)); if (expected > 0) { output.resize(expected + 1); UINT32 fetched = 0; THROW_IF_FAILED(src->GetMany(0, static_cast(output.size()), reinterpret_cast(output.data()), &fetched)); THROW_HR_IF(E_CHANGED_STATE, fetched > expected); output.resize(fetched); } return output; } #endif #pragma region error code base IIterable<> __WI_ITR_NAMESPACE_BEGIN template class iterable_range_nothrow { public: typedef typename details::MapIteratorResultType::type TResult; typedef typename details::MapToSmartType::type TSmart; iterable_range_nothrow() = delete; iterable_range_nothrow(const iterable_range_nothrow&) = delete; iterable_range_nothrow& operator=(const iterable_range_nothrow&) = delete; iterable_range_nothrow& operator=(iterable_range_nothrow&&) = delete; iterable_range_nothrow(iterable_range_nothrow&& other) WI_NOEXCEPT : m_iterator(wistd::move(other.m_iterator)), m_element(wistd::move(other.m_element)), m_resultStorage(other.m_resultStorage) #if WIL_ITERATOR_DEBUG_LEVEL > 0 , m_index(other.m_index) #endif { if (other.m_result == &other.m_resultStorage) { m_result = &m_resultStorage; } else { m_result = other.m_result; } } iterable_range_nothrow(_In_ ABI::Windows::Foundation::Collections::IIterable* iterable, HRESULT* result = nullptr) : m_result(result ? result : &m_resultStorage) { *m_result = iterable->First(&m_iterator); if (SUCCEEDED(*m_result)) { boolean hasCurrent; *m_result = m_iterator->get_HasCurrent(&hasCurrent); if (SUCCEEDED(*m_result) && hasCurrent) { *m_result = m_iterator->get_Current(m_element.ReleaseAndGetAddressOf()); if (FAILED(*m_result)) { m_iterator = nullptr; // release the iterator if no elements are found } } else { m_iterator = nullptr; // release the iterator if no elements are found } } } class iterable_iterator_nothrow { public: #if defined(_XUTILITY_) || defined(WIL_DOXYGEN) // muse be input_iterator_tag as use of one instance invalidates the other. typedef ::std::input_iterator_tag iterator_category; #endif typedef TSmart value_type; typedef ptrdiff_t difference_type; typedef const TSmart* pointer; typedef const TSmart& reference; iterable_iterator_nothrow(_In_ iterable_range_nothrow* range, int currentIndex) : m_range(range), m_i(currentIndex) { } WI_NODISCARD bool operator==(iterable_iterator_nothrow const& other) const { return FAILED(*m_range->m_result) || (m_i == other.m_i); } WI_NODISCARD bool operator!=(iterable_iterator_nothrow const& other) const { return !operator==(other); } WI_NODISCARD reference operator*() const WI_NOEXCEPT { return *this->operator->(); } WI_NODISCARD pointer operator->() const WI_NOEXCEPT { #if WIL_ITERATOR_DEBUG_LEVEL > 0 WI_FAIL_FAST_ASSERT_MSG(SUCCEEDED(*m_range->m_result), "Dereferencing an iterable_iterator_nothrow in a failed state"); WI_FAIL_FAST_ASSERT_MSG(m_i >= 0, "Dereferencing an 'end' iterator"); WI_FAIL_FAST_ASSERT_MSG(m_i == m_range->m_index, "Dereferencing an out-of-date iterable_iterator_nothrow"); #endif return wistd::addressof(m_range->m_element); } iterable_iterator_nothrow& operator++() { #if WIL_ITERATOR_DEBUG_LEVEL > 0 // Failing this check is always bad because the iterator object we hold always advances forward WI_FAIL_FAST_ASSERT_MSG(m_i >= 0, "Incrementing an end iterator"); WI_FAIL_FAST_ASSERT_MSG(m_i == m_range->m_index, "Incrementing an out-of-date copy of an iterable_iterator_nothrow"); #endif boolean hasCurrent; *m_range->m_result = m_range->m_iterator->MoveNext(&hasCurrent); if (SUCCEEDED(*m_range->m_result) && hasCurrent) { *m_range->m_result = m_range->m_iterator->get_Current(m_range->m_element.ReleaseAndGetAddressOf()); if (SUCCEEDED(*m_range->m_result)) { m_i++; } else { m_i = -1; } } else { m_i = -1; } #if WIL_ITERATOR_DEBUG_LEVEL > 0 m_range->m_index = m_i; #endif return *this; } iterable_iterator_nothrow operator++(int) { iterable_iterator_nothrow old(*this); ++*this; return old; } private: iterable_range_nothrow* m_range; int m_i; }; iterable_iterator_nothrow begin() { #if WIL_ITERATOR_DEBUG_LEVEL == 2 // The IIterator we hold only advances forward; we can't reset it back to the beginning. Calling this method more than // once will very likely lead to unexpected behavior. WI_FAIL_FAST_ASSERT_MSG(m_index == 0, "Calling begin() on an already advanced iterable_range_nothrow"); #endif return iterable_iterator_nothrow(this, this->m_iterator ? 0 : -1); } iterable_iterator_nothrow end() { return iterable_iterator_nothrow(this, -1); } private: Microsoft::WRL::ComPtr> m_iterator; // This state is shared by all iterator instances // so use of one iterator can invalidate another's ability to dereference // that is allowed for input iterators. TSmart m_element; HRESULT* m_result; HRESULT m_resultStorage = S_OK; #if WIL_ITERATOR_DEBUG_LEVEL > 0 // For checked iterator support int m_index = 0; #endif }; __WI_ITR_NAMESPACE_END #pragma endregion #ifdef WIL_ENABLE_EXCEPTIONS template vector_range> get_range(ABI::Windows::Foundation::Collections::IVector* v) { return vector_range>(v); } template vector_range> get_range(ABI::Windows::Foundation::Collections::IVectorView* v) { return vector_range>(v); } #endif // WIL_ENABLE_EXCEPTIONS template vector_range, err_failfast_policy> get_range_failfast( ABI::Windows::Foundation::Collections::IVector* v) { return vector_range, err_failfast_policy>(v); } template vector_range, err_failfast_policy> get_range_failfast( ABI::Windows::Foundation::Collections::IVectorView* v) { return vector_range, err_failfast_policy>(v); } template vector_range_nothrow> get_range_nothrow( ABI::Windows::Foundation::Collections::IVector* v, HRESULT* result = nullptr) { return vector_range_nothrow>(v, result); } template vector_range_nothrow> get_range_nothrow( ABI::Windows::Foundation::Collections::IVectorView* v, HRESULT* result = nullptr) { return vector_range_nothrow>(v, result); } #ifdef WIL_ENABLE_EXCEPTIONS template iterable_range get_range(ABI::Windows::Foundation::Collections::IIterable* v) { return iterable_range(v); } #endif // WIL_ENABLE_EXCEPTIONS template iterable_range get_range_failfast(ABI::Windows::Foundation::Collections::IIterable* v) { return iterable_range(v); } template iterable_range_nothrow get_range_nothrow(ABI::Windows::Foundation::Collections::IIterable* v, HRESULT* result = nullptr) { return iterable_range_nothrow(v, result); } #pragma endregion } // namespace wil #ifdef WIL_ENABLE_EXCEPTIONS #pragma region Global operator functions #if defined(MIDL_NS_PREFIX) || defined(____x_ABI_CWindows_CFoundation_CIClosable_FWD_DEFINED__) namespace ABI { #endif namespace Windows { namespace Foundation { namespace Collections { template typename wil::vector_range>::vector_iterator begin(IVector* v) { return typename wil::vector_range>::vector_iterator(v, 0); } template typename wil::vector_range>::vector_iterator end(IVector* v) { unsigned int size; THROW_IF_FAILED(v->get_Size(&size)); return typename wil::vector_range>::vector_iterator(v, size); } template typename wil::vector_range>::vector_iterator begin(IVectorView* v) { return typename wil::vector_range>::vector_iterator(v, 0); } template typename wil::vector_range>::vector_iterator end(IVectorView* v) { unsigned int size; THROW_IF_FAILED(v->get_Size(&size)); return typename wil::vector_range>::vector_iterator(v, size); } template typename wil::iterable_range::iterable_iterator begin(IIterable* i) { return typename wil::iterable_range::iterable_iterator(i); } template typename wil::iterable_range::iterable_iterator end(IIterable*) { return typename wil::iterable_range::iterable_iterator(); } } // namespace Collections } // namespace Foundation } // namespace Windows #if defined(MIDL_NS_PREFIX) || defined(____x_ABI_CWindows_CFoundation_CIClosable_FWD_DEFINED__) } // namespace ABI #endif #pragma endregion #endif // WIL_ENABLE_EXCEPTIONS namespace wil { #pragma region WinRT Async API helpers /// @cond namespace details { template ::value, int>::type = 0> HRESULT CallAndHandleErrorsWithReturnType(TFunc&& func, Args&&... args) { return wistd::forward(func)(wistd::forward(args)...); } #ifdef WIL_ENABLE_EXCEPTIONS template ::value, int>::type = 0> HRESULT CallAndHandleErrorsWithReturnType(TFunc&& func, Args&&... args) { try { wistd::forward(func)(wistd::forward(args)...); } CATCH_RETURN(); return S_OK; } #endif template HRESULT CallAndHandleErrors(TFunc&& func, Args&&... args) { return CallAndHandleErrorsWithReturnType(func)(wistd::forward(args)...))>( wistd::forward(func), wistd::forward(args)...); } // Get the last type of a template parameter pack. // usage: // LastType::type boolValue; template struct LastType { template struct LastTypeOfTs { typedef typename LastTypeOfTs::type type; }; template struct LastTypeOfTs { typedef T type; }; template static typename LastTypeOfTs::type LastTypeOfTsFunc() { } typedef decltype(LastTypeOfTsFunc()) type; }; // Takes a member function that has an out param like F(..., IAsyncAction**) or F(..., IAsyncOperation**) // and returns IAsyncAction* or IAsyncOperation*. template typename wistd::remove_pointer::type>::type GetReturnParamPointerType(HRESULT (STDMETHODCALLTYPE I::*)(P...)); // Use to determine the result type of the async action/operation interfaces or example // decltype(GetAsyncResultType(action.get())) returns void void GetAsyncResultType(ABI::Windows::Foundation::IAsyncAction*); template void GetAsyncResultType(ABI::Windows::Foundation::IAsyncActionWithProgress

*); template typename wil::details::MapAsyncOpResultType::type GetAsyncResultType(ABI::Windows::Foundation::IAsyncOperation*); template typename wil::details::MapAsyncOpProgressResultType::type GetAsyncResultType( ABI::Windows::Foundation::IAsyncOperationWithProgress*); // Use to determine the result type of the async action/operation interfaces or example // decltype(GetAsyncDelegateType(action.get())) returns void ABI::Windows::Foundation::IAsyncActionCompletedHandler* GetAsyncDelegateType(ABI::Windows::Foundation::IAsyncAction*); template ABI::Windows::Foundation::IAsyncActionWithProgressCompletedHandler

* GetAsyncDelegateType( ABI::Windows::Foundation::IAsyncActionWithProgress

*); template ABI::Windows::Foundation::IAsyncOperationCompletedHandler* GetAsyncDelegateType(ABI::Windows::Foundation::IAsyncOperation*); template ABI::Windows::Foundation::IAsyncOperationWithProgressCompletedHandler* GetAsyncDelegateType( ABI::Windows::Foundation::IAsyncOperationWithProgress*); template HRESULT RunWhenCompleteAction(_In_ TIOperation operation, TFunction&& func) WI_NOEXCEPT { using namespace Microsoft::WRL; typedef wistd::remove_pointer_t TIDelegate; auto callback = Callback, TIDelegate, TBaseAgility>>( [func = wistd::forward(func)](TIOperation operation, ABI::Windows::Foundation::AsyncStatus status) mutable -> HRESULT { HRESULT hr = S_OK; if (status != ABI::Windows::Foundation::AsyncStatus::Completed) // avoid a potentially costly marshaled QI / call if we completed successfully { // QI to the IAsyncInfo interface. While all operations implement this, it is // possible that the stub has disconnected, causing the QI to fail. ComPtr asyncInfo; hr = operation->QueryInterface(IID_PPV_ARGS(&asyncInfo)); if (SUCCEEDED(hr)) { // Save the error code result in a temporary variable to allow us // to also retrieve the result of the COM call. If the stub has // disconnected, this call may fail. HRESULT errorCode = E_UNEXPECTED; hr = asyncInfo->get_ErrorCode(&errorCode); if (SUCCEEDED(hr)) { // Return the operations error code to the caller. hr = errorCode; } } } return CallAndHandleErrors(func, hr); }); RETURN_IF_NULL_ALLOC(callback); return operation->put_Completed(callback.Get()); } template HRESULT RunWhenComplete(_In_ TIOperation operation, TFunction&& func) WI_NOEXCEPT { using namespace Microsoft::WRL; using namespace ABI::Windows::Foundation::Internal; typedef wistd::remove_pointer_t TIDelegate; auto callback = Callback, TIDelegate, TBaseAgility>>( [func = wistd::forward(func)](TIOperation operation, ABI::Windows::Foundation::AsyncStatus status) mutable -> HRESULT { typename details::MapToSmartType::type::TResult_complex>::type>::type result; HRESULT hr = S_OK; // avoid a potentially costly marshaled QI / call if we completed successfully if (status == ABI::Windows::Foundation::AsyncStatus::Completed) { hr = operation->GetResults(result.GetAddressOf()); } else { // QI to the IAsyncInfo interface. While all operations implement this, it is // possible that the stub has disconnected, causing the QI to fail. ComPtr asyncInfo; hr = operation->QueryInterface(IID_PPV_ARGS(&asyncInfo)); if (SUCCEEDED(hr)) { // Save the error code result in a temporary variable to allow us // to also retrieve the result of the COM call. If the stub has // disconnected, this call may fail. HRESULT errorCode = E_UNEXPECTED; hr = asyncInfo->get_ErrorCode(&errorCode); if (SUCCEEDED(hr)) { // Return the operations error code to the caller. hr = errorCode; } } } return CallAndHandleErrors(func, hr, result.Get()); }); RETURN_IF_NULL_ALLOC(callback); return operation->put_Completed(callback.Get()); } #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM) template HRESULT WaitForCompletion(_In_ TIOperation operation, COWAIT_FLAGS flags, DWORD timeoutValue, _Out_opt_ bool* timedOut) WI_NOEXCEPT { typedef wistd::remove_pointer_t TIDelegate; class CompletionDelegate : public Microsoft::WRL::RuntimeClass, TIDelegate, Microsoft::WRL::FtmBase> { public: HRESULT RuntimeClassInitialize() { RETURN_HR(m_completedEventHandle.create()); } HRESULT STDMETHODCALLTYPE Invoke(_In_ TIOperation, ABI::Windows::Foundation::AsyncStatus status) override { m_status = status; m_completedEventHandle.SetEvent(); return S_OK; } WI_NODISCARD HANDLE GetEvent() const { return m_completedEventHandle.get(); } WI_NODISCARD ABI::Windows::Foundation::AsyncStatus GetStatus() const { return m_status; } private: volatile ABI::Windows::Foundation::AsyncStatus m_status = ABI::Windows::Foundation::AsyncStatus::Started; wil::unique_event_nothrow m_completedEventHandle; }; WI_ASSERT(timedOut || (timeoutValue == INFINITE)); assign_to_opt_param(timedOut, false); Microsoft::WRL::ComPtr completedDelegate; RETURN_IF_FAILED(Microsoft::WRL::MakeAndInitialize(&completedDelegate)); RETURN_IF_FAILED(operation->put_Completed(completedDelegate.Get())); HANDLE handles[] = {completedDelegate->GetEvent()}; DWORD dwHandleIndex; HRESULT hr = CoWaitForMultipleHandles(flags, timeoutValue, ARRAYSIZE(handles), handles, &dwHandleIndex); // If the caller is listening for timedOut, and we actually timed out, set the bool and return S_OK. Otherwise, fail. if (timedOut && (hr == RPC_S_CALLPENDING)) { *timedOut = true; return S_OK; } RETURN_IF_FAILED(hr); if (completedDelegate->GetStatus() != ABI::Windows::Foundation::AsyncStatus::Completed) { // QI to the IAsyncInfo interface. While all operations implement this, it is // possible that the stub has disconnected, causing the QI to fail. Microsoft::WRL::ComPtr asyncInfo; hr = operation->QueryInterface(IID_PPV_ARGS(&asyncInfo)); if (SUCCEEDED(hr)) { // Save the error code result in a temporary variable to allow us // to also retrieve the result of the COM call. If the stub has // disconnected, this call may fail. HRESULT errorCode = E_UNEXPECTED; hr = asyncInfo->get_ErrorCode(&errorCode); if (SUCCEEDED(hr)) { // Return the operations error code to the caller. hr = errorCode; } } return hr; // leave it to the caller to log failures. } return S_OK; } template HRESULT WaitForCompletion(_In_ TIOperation operation, _Out_ TIResults result, COWAIT_FLAGS flags, DWORD timeoutValue, _Out_opt_ bool* timedOut) WI_NOEXCEPT { RETURN_IF_FAILED_EXPECTED(details::WaitForCompletion(operation, flags, timeoutValue, timedOut)); return operation->GetResults(result); } #endif // WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM) } // namespace details /// @endcond /** Set the completion callback for an async operation to run a caller provided function. Once complete the function is called with the error code result of the operation and the async operation result (if applicable). The function parameter list must be (HRESULT hr) for actions, (HRESULT hr, IResultInterface* object) for operations that produce interfaces, and (HRESULT hr, TResult value) for operations that produce value types. ~~~ run_when_complete(getFileOp.Get(), [](HRESULT hr, IStorageFile* file) -> void { }); ~~~ for an agile callback use Microsoft::WRL::FtmBase ~~~ run_when_complete(getFileOp.Get(), [](HRESULT hr, IStorageFile* file) -> void { }); ~~~ Using the non throwing form: ~~~ hr = run_when_complete_nothrow(getFileOp.Get(), [](HRESULT hr, IStorageFile* file) -> HRESULT { }); ~~~ */ //! Run a fuction when an async operation completes. Use Microsoft::WRL::FtmBase for TAgility to make the completion handler agile //! and run on the async thread. template HRESULT run_when_complete_nothrow(_In_ ABI::Windows::Foundation::IAsyncAction* operation, TFunc&& func) WI_NOEXCEPT { return details::RunWhenCompleteAction(operation, wistd::forward(func)); } template ::type> HRESULT run_when_complete_nothrow(_In_ ABI::Windows::Foundation::IAsyncOperation* operation, TFunc&& func) WI_NOEXCEPT { return details::RunWhenComplete(operation, wistd::forward(func)); } template ::type> HRESULT run_when_complete_nothrow(_In_ ABI::Windows::Foundation::IAsyncOperationWithProgress* operation, TFunc&& func) WI_NOEXCEPT { return details::RunWhenComplete(operation, wistd::forward(func)); } template HRESULT run_when_complete_nothrow(_In_ ABI::Windows::Foundation::IAsyncActionWithProgress* operation, TFunc&& func) WI_NOEXCEPT { return details::RunWhenCompleteAction(operation, wistd::forward(func)); } #ifdef WIL_ENABLE_EXCEPTIONS //! Run a fuction when an async operation completes. Use Microsoft::WRL::FtmBase for TAgility to make the completion handler agile //! and run on the async thread. template void run_when_complete(_In_ ABI::Windows::Foundation::IAsyncAction* operation, TFunc&& func) { THROW_IF_FAILED((details::RunWhenCompleteAction(operation, wistd::forward(func)))); } template ::type> void run_when_complete(_In_ ABI::Windows::Foundation::IAsyncOperation* operation, TFunc&& func) { THROW_IF_FAILED((details::RunWhenComplete(operation, wistd::forward(func)))); } template ::type> void run_when_complete(_In_ ABI::Windows::Foundation::IAsyncOperationWithProgress* operation, TFunc&& func) { THROW_IF_FAILED((details::RunWhenComplete(operation, wistd::forward(func)))); } template void run_when_complete(_In_ ABI::Windows::Foundation::IAsyncActionWithProgress* operation, TFunc&& func) { THROW_IF_FAILED((details::RunWhenCompleteAction(operation, wistd::forward(func)))); } #endif #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM) /** Wait for an asynchronous operation to complete (or be canceled). Use to synchronously wait on async operations on background threads. Do not call from UI threads or STA threads as reentrancy will result. ~~~ ComPtr> op; THROW_IF_FAILED(storageFileStatics->GetFileFromPathAsync(HStringReference(path).Get(), &op)); auto file = wil::wait_for_completion(op.Get()); ~~~ */ template inline HRESULT wait_for_completion_nothrow(_In_ TAsync* operation, COWAIT_FLAGS flags = COWAIT_DISPATCH_CALLS) WI_NOEXCEPT { return details::WaitForCompletion(operation, flags, INFINITE, nullptr); } // These forms return the result from the async operation template HRESULT wait_for_completion_nothrow( _In_ ABI::Windows::Foundation::IAsyncOperation* operation, _Out_ typename wil::details::MapAsyncOpResultType::type* result, COWAIT_FLAGS flags = COWAIT_DISPATCH_CALLS) WI_NOEXCEPT { return details::WaitForCompletion(operation, result, flags, INFINITE, nullptr); } template HRESULT wait_for_completion_nothrow( _In_ ABI::Windows::Foundation::IAsyncOperationWithProgress* operation, _Out_ typename wil::details::MapAsyncOpProgressResultType::type* result, COWAIT_FLAGS flags = COWAIT_DISPATCH_CALLS) WI_NOEXCEPT { return details::WaitForCompletion(operation, result, flags, INFINITE, nullptr); } // Same as above, but allows caller to specify a timeout value. // On timeout, S_OK is returned, with timedOut set to true. template inline HRESULT wait_for_completion_or_timeout_nothrow( _In_ TAsync* operation, DWORD timeoutValue, _Out_ bool* timedOut, COWAIT_FLAGS flags = COWAIT_DISPATCH_CALLS) WI_NOEXCEPT { return details::WaitForCompletion(operation, flags, timeoutValue, timedOut); } template HRESULT wait_for_completion_or_timeout_nothrow( _In_ ABI::Windows::Foundation::IAsyncOperation* operation, _Out_ typename wil::details::MapAsyncOpResultType::type* result, DWORD timeoutValue, _Out_ bool* timedOut, COWAIT_FLAGS flags = COWAIT_DISPATCH_CALLS) WI_NOEXCEPT { return details::WaitForCompletion(operation, result, flags, timeoutValue, timedOut); } template HRESULT wait_for_completion_or_timeout_nothrow( _In_ ABI::Windows::Foundation::IAsyncOperationWithProgress* operation, _Out_ typename wil::details::MapAsyncOpProgressResultType::type* result, DWORD timeoutValue, _Out_ bool* timedOut, COWAIT_FLAGS flags = COWAIT_DISPATCH_CALLS) WI_NOEXCEPT { return details::WaitForCompletion(operation, result, flags, timeoutValue, timedOut); } #ifdef WIL_ENABLE_EXCEPTIONS //! Wait for an asynchronous operation to complete (or be canceled). template inline void wait_for_completion(_In_ TAsync* operation, COWAIT_FLAGS flags = COWAIT_DISPATCH_CALLS) { THROW_IF_FAILED(details::WaitForCompletion(operation, flags, INFINITE, nullptr)); } template ::type>::type> TReturn wait_for_completion(_In_ ABI::Windows::Foundation::IAsyncOperation* operation, COWAIT_FLAGS flags = COWAIT_DISPATCH_CALLS) { TReturn result; THROW_IF_FAILED(details::WaitForCompletion(operation, result.GetAddressOf(), flags, INFINITE, nullptr)); return result; } template < typename TResult, typename TProgress, typename TReturn = typename wil::details::MapToSmartType::type>::type> TReturn wait_for_completion(_In_ ABI::Windows::Foundation::IAsyncOperationWithProgress* operation, COWAIT_FLAGS flags = COWAIT_DISPATCH_CALLS) { TReturn result; THROW_IF_FAILED(details::WaitForCompletion(operation, result.GetAddressOf(), flags, INFINITE, nullptr)); return result; } /** Similar to WaitForCompletion but this function encapsulates the creation of the async operation making usage simpler. ~~~ ComPtr launcher; // inited somewhere auto result = call_and_wait_for_completion(launcher.Get(), &ILauncherStatics::LaunchUriAsync, uri.Get()); ~~~ */ template auto call_and_wait_for_completion(I* object, HRESULT (STDMETHODCALLTYPE I::*func)(P...), Args&&... args) { Microsoft::WRL::ComPtr::type>::type>::type> op; THROW_IF_FAILED((object->*func)(wistd::forward(args)..., &op)); return wil::wait_for_completion(op.Get()); } #endif #endif // WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM) #pragma endregion #pragma region WinRT object construction #ifdef WIL_ENABLE_EXCEPTIONS //! Get a WinRT activation factory object, usually using a IXXXStatics interface. template com_ptr GetActivationFactory(PCWSTR runtimeClass) { com_ptr result; THROW_IF_FAILED(RoGetActivationFactory(Microsoft::WRL::Wrappers::HStringReference(runtimeClass).Get(), IID_PPV_ARGS(&result))); return result; } //! Get a WinRT object. template com_ptr ActivateInstance(PCWSTR runtimeClass) { com_ptr result; THROW_IF_FAILED(RoActivateInstance(Microsoft::WRL::Wrappers::HStringReference(runtimeClass).Get(), &result)); return result.query(); } #endif #pragma endregion #pragma region Async production helpers /// @cond namespace details { template class SyncAsyncOp WrlFinal : public Microsoft::WRL::RuntimeClass< ABI::Windows::Foundation::IAsyncOperation, Microsoft::WRL::AsyncBase>> { // typedef typename MapToSmartType::type TSmart; using RuntimeClassT = typename SyncAsyncOp::RuntimeClassT; InspectableClass(__super::z_get_rc_name_impl(), TrustLevel::BaseTrust); public: HRESULT RuntimeClassInitialize(const TResult& op) { m_result = op; return S_OK; } IFACEMETHODIMP put_Completed(ABI::Windows::Foundation::IAsyncOperationCompletedHandler* competed) override { competed->Invoke(this, ABI::Windows::Foundation::AsyncStatus::Completed); return S_OK; } IFACEMETHODIMP get_Completed(ABI::Windows::Foundation::IAsyncOperationCompletedHandler** competed) override { *competed = nullptr; return S_OK; } IFACEMETHODIMP GetResults(TResult* result) override { *result = m_result; return S_OK; } HRESULT OnStart() override { return S_OK; } void OnClose() override { } void OnCancel() override { } private: // needs to be MapToSmartType::type to hold non trial types TResult m_result{}; }; extern const __declspec(selectany) wchar_t SyncAsyncActionName[] = L"SyncActionAction"; class SyncAsyncActionOp WrlFinal : public Microsoft::WRL::RuntimeClass< ABI::Windows::Foundation::IAsyncAction, Microsoft::WRL::AsyncBase< ABI::Windows::Foundation::IAsyncActionCompletedHandler, Microsoft::WRL::Details::Nil, Microsoft::WRL::AsyncResultType::SingleResult #ifndef _WRL_DISABLE_CAUSALITY_ , Microsoft::WRL::AsyncCausalityOptions #endif >> { InspectableClass(InterfaceName_Windows_Foundation_IAsyncAction, TrustLevel::BaseTrust); public: IFACEMETHODIMP put_Completed(ABI::Windows::Foundation::IAsyncActionCompletedHandler* competed) override { competed->Invoke(this, ABI::Windows::Foundation::AsyncStatus::Completed); return S_OK; } IFACEMETHODIMP get_Completed(ABI::Windows::Foundation::IAsyncActionCompletedHandler** competed) override { *competed = nullptr; return S_OK; } IFACEMETHODIMP GetResults() override { return S_OK; } HRESULT OnStart() override { return S_OK; } void OnClose() override { } void OnCancel() override { } }; } // namespace details /// @endcond //! Creates a WinRT async operation object that implements IAsyncOperation. Use mostly for testing and for mocking APIs. template HRESULT make_synchronous_async_operation_nothrow(ABI::Windows::Foundation::IAsyncOperation** result, const TResult& value) { return Microsoft::WRL::MakeAndInitialize>(result, value); } //! Creates a WinRT async operation object that implements IAsyncAction. Use mostly for testing and for mocking APIs. inline HRESULT make_synchronous_async_action_nothrow(ABI::Windows::Foundation::IAsyncAction** result) { return Microsoft::WRL::MakeAndInitialize(result); } #ifdef WIL_ENABLE_EXCEPTIONS //! Creates a WinRT async operation object that implements IAsyncOperation. Use mostly for testing and for mocking APIs. // TODO: map TRealResult and TSmartResult into SyncAsyncOp. template ::type, typename TSmartResult = typename details::MapToSmartType::type> void make_synchronous_async_operation(ABI::Windows::Foundation::IAsyncOperation** result, const TResult& value) { THROW_IF_FAILED((Microsoft::WRL::MakeAndInitialize>(result, value))); } //! Creates a WinRT async operation object that implements IAsyncAction. Use mostly for testing and for mocking APIs. inline void make_synchronous_async_action(ABI::Windows::Foundation::IAsyncAction** result) { THROW_IF_FAILED((Microsoft::WRL::MakeAndInitialize(result))); } #endif #pragma endregion #pragma region EventRegistrationToken RAII wrapper // unique_winrt_event_token[_cx] is an RAII wrapper around EventRegistrationToken. When the unique_winrt_event_token[_cx] is // destroyed, the event is automatically unregistered. Declare a wil::unique_winrt_event_token[_cx] at the scope the event // should be registered for (often they are tied to object lifetime), where T is the type of the event sender // wil::unique_winrt_event_token_cx m_token; // // Macros have been defined to register for handling the event and then returning an unique_winrt_event_token[_cx]. These // macros simply hide the function references for adding and removing the event. // C++/CX m_token = WI_MakeUniqueWinRtEventTokenCx(ExampleEventName, sender, handler); // ABI m_token = WI_MakeUniqueWinRtEventToken(ExampleEventName, sender, handler, &m_token); // Exception and failfast // ABI RETURN_IF_FAILED(WI_MakeUniqueWinRtEventTokenNoThrow(ExampleEventName, sender, handler, &m_token)); // No throw variant // // When the wrapper is destroyed, the handler will be unregistered. You can explicitly unregister the handler prior. // m_token.reset(); // // You can release the EventRegistrationToken from being managed by the wrapper by calling .release() // m_token.release(); // DANGER: no longer being managed // // If you just need the value of the EventRegistrationToken you can call .get() // m_token.get(); // // See "onecore\shell\tests\wil\UniqueWinRTEventTokenTests.cpp" for more examples of usage in ABI and C++/CX. // clang-format off #ifdef __cplusplus_winrt namespace details { template struct remove_reference { typedef T type; }; template struct remove_reference { typedef T type; }; } // namespace details template class unique_winrt_event_token_cx { using removal_func = void (T::*)(Windows::Foundation::EventRegistrationToken); using static_removal_func = void(__cdecl*)(Windows::Foundation::EventRegistrationToken); public: unique_winrt_event_token_cx() = default; unique_winrt_event_token_cx(Windows::Foundation::EventRegistrationToken token, T^ sender, removal_func removalFunction) WI_NOEXCEPT : m_token(token), m_weakSender(sender), m_removalFunction(removalFunction) { } unique_winrt_event_token_cx(Windows::Foundation::EventRegistrationToken token, static_removal_func removalFunction) WI_NOEXCEPT : m_token(token), m_staticRemovalFunction(removalFunction) { } unique_winrt_event_token_cx(const unique_winrt_event_token_cx&) = delete; unique_winrt_event_token_cx& operator=(const unique_winrt_event_token_cx&) = delete; unique_winrt_event_token_cx(unique_winrt_event_token_cx&& other) WI_NOEXCEPT : m_token(other.m_token), m_weakSender(wistd::move(other.m_weakSender)), m_removalFunction(other.m_removalFunction), m_staticRemovalFunction(other.m_staticRemovalFunction) { other.m_token = {}; other.m_weakSender = nullptr; other.m_removalFunction = nullptr; other.m_staticRemovalFunction = nullptr; } unique_winrt_event_token_cx& operator=(unique_winrt_event_token_cx&& other) WI_NOEXCEPT { if (this != wistd::addressof(other)) { reset(); wistd::swap_wil(m_token, other.m_token); wistd::swap_wil(m_weakSender, other.m_weakSender); wistd::swap_wil(m_removalFunction, other.m_removalFunction); wistd::swap_wil(m_staticRemovalFunction, other.m_staticRemovalFunction); } return *this; } ~unique_winrt_event_token_cx() WI_NOEXCEPT { reset(); } WI_NODISCARD explicit operator bool() const WI_NOEXCEPT { return (m_token.Value != 0); } WI_NODISCARD Windows::Foundation::EventRegistrationToken get() const WI_NOEXCEPT { return m_token; } void reset() noexcept { if (m_token.Value != 0) { if (m_staticRemovalFunction) { (*m_staticRemovalFunction)(m_token); } else { auto resolvedSender = [&]() { try { return m_weakSender.Resolve(); } catch (...) { // Ignore RPC or other failures that are unavoidable in some cases // matching wil::unique_winrt_event_token and winrt::event_revoker return static_cast(nullptr); } }(); if (resolvedSender) { (resolvedSender->*m_removalFunction)(m_token); } } release(); } } // Stops the wrapper from managing resource and returns the EventRegistrationToken. Windows::Foundation::EventRegistrationToken release() WI_NOEXCEPT { auto token = m_token; m_token = {}; m_weakSender = nullptr; m_removalFunction = nullptr; m_staticRemovalFunction = nullptr; return token; } private: Windows::Foundation::EventRegistrationToken m_token = {}; Platform::WeakReference m_weakSender; removal_func m_removalFunction = nullptr; static_removal_func m_staticRemovalFunction = nullptr; }; #endif // clang-format on template class unique_winrt_event_token { using removal_func = HRESULT (__stdcall T::*)(::EventRegistrationToken); public: unique_winrt_event_token() = default; unique_winrt_event_token(::EventRegistrationToken token, T* sender, removal_func removalFunction) WI_NOEXCEPT : m_token(token), m_removalFunction(removalFunction) { m_weakSender = wil::com_weak_query_failfast(sender); } unique_winrt_event_token(const unique_winrt_event_token&) = delete; unique_winrt_event_token& operator=(const unique_winrt_event_token&) = delete; unique_winrt_event_token(unique_winrt_event_token&& other) WI_NOEXCEPT : m_token(other.m_token), m_weakSender(wistd::move(other.m_weakSender)), m_removalFunction(other.m_removalFunction) { other.m_token = {}; other.m_removalFunction = nullptr; } unique_winrt_event_token& operator=(unique_winrt_event_token&& other) WI_NOEXCEPT { if (this != wistd::addressof(other)) { reset(); wistd::swap_wil(m_token, other.m_token); wistd::swap_wil(m_weakSender, other.m_weakSender); wistd::swap_wil(m_removalFunction, other.m_removalFunction); } return *this; } ~unique_winrt_event_token() WI_NOEXCEPT { reset(); } WI_NODISCARD explicit operator bool() const WI_NOEXCEPT { return (m_token.value != 0); } WI_NODISCARD ::EventRegistrationToken get() const WI_NOEXCEPT { return m_token; } void reset() WI_NOEXCEPT { if (m_token.value != 0) { // If T cannot be QI'ed from the weak object then T is not a COM interface. auto resolvedSender = m_weakSender.try_query(); if (resolvedSender) { FAIL_FAST_IF_FAILED((resolvedSender.get()->*m_removalFunction)(m_token)); } release(); } } // Stops the wrapper from managing resource and returns the EventRegistrationToken. ::EventRegistrationToken release() WI_NOEXCEPT { auto token = m_token; m_token = {}; m_weakSender = nullptr; m_removalFunction = nullptr; return token; } private: ::EventRegistrationToken m_token = {}; wil::com_weak_ref_failfast m_weakSender; removal_func m_removalFunction = nullptr; }; /// @cond namespace details { // clang-format off #ifdef __cplusplus_winrt // Handles registration of the event handler to the subscribing object and then wraps the EventRegistrationToken in unique_winrt_event_token. // Not intended to be directly called. Use the WI_MakeUniqueWinRtEventTokenCx macro to abstract away specifying the functions that handle addition and removal. template inline wil::unique_winrt_event_token_cx make_unique_winrt_event_token_cx( T^ sender, addition_func additionFunc, removal_func removalFunc, handler^ h) { auto rawToken = (sender->*additionFunc)(h); wil::unique_winrt_event_token_cx temp(rawToken, sender, removalFunc); return temp; } template inline wil::unique_winrt_event_token_cx make_unique_winrt_static_event_token_cx( addition_func additionFunc, removal_func removalFunc, handler^ h) { auto rawToken = (*additionFunc)(h); wil::unique_winrt_event_token_cx temp(rawToken, removalFunc); return temp; } #endif // __cplusplus_winrt // clang-format on // Handles registration of the event handler to the subscribing object and then wraps the EventRegistrationToken in unique_winrt_event_token. // Not intended to be directly called. Use the WI_MakeUniqueWinRtEventToken macro to abstract away specifying the functions that handle addition and removal. template inline auto make_unique_winrt_event_token( T* sender, addition_func additionFunc, removal_func removalFunc, handler h, wil::unique_winrt_event_token* token_reference) { ::EventRegistrationToken rawToken; err_policy::HResult((sender->*additionFunc)(h, &rawToken)); *token_reference = wil::unique_winrt_event_token(rawToken, sender, removalFunc); return err_policy::OK(); } // Overload make function to allow for returning the constructed object when not using HRESULT based code. template inline typename wistd::enable_if::value, wil::unique_winrt_event_token>::type make_unique_winrt_event_token( T* sender, addition_func additionFunc, removal_func removalFunc, handler h) { ::EventRegistrationToken rawToken; err_policy::HResult((sender->*additionFunc)(h, &rawToken)); return wil::unique_winrt_event_token(rawToken, sender, removalFunc); } } // namespace details /// @endcond // Helper macros to abstract function names for event addition and removal. #ifdef __cplusplus_winrt #define WI_MakeUniqueWinRtEventTokenCx(_event, _object, _handler) \ wil::details::make_unique_winrt_event_token_cx( \ _object, \ &wil::details::remove_reference::type::##_event## ::add, \ &wil::details::remove_reference::type::##_event## ::remove, \ _handler) #define WI_MakeUniqueWinRtStaticEventTokenCx(_event, _baseType, _handler) \ wil::details::make_unique_winrt_static_event_token_cx<_baseType>( \ &##_baseType## ::##_event## ::add, &##_baseType## ::##_event## ::remove, _handler) #endif // __cplusplus_winrt #ifdef WIL_ENABLE_EXCEPTIONS #define WI_MakeUniqueWinRtEventToken(_event, _object, _handler) \ wil::details::make_unique_winrt_event_token( \ _object, \ &wistd::remove_pointer::type::add_##_event, \ &wistd::remove_pointer::type::remove_##_event, \ _handler) #endif // WIL_ENABLE_EXCEPTIONS #define WI_MakeUniqueWinRtEventTokenNoThrow(_event, _object, _handler, _token_reference) \ wil::details::make_unique_winrt_event_token( \ _object, \ &wistd::remove_pointer::type::add_##_event, \ &wistd::remove_pointer::type::remove_##_event, \ _handler, \ _token_reference) #define WI_MakeUniqueWinRtEventTokenFailFast(_event, _object, _handler) \ wil::details::make_unique_winrt_event_token( \ _object, \ &wistd::remove_pointer::type::add_##_event, \ &wistd::remove_pointer::type::remove_##_event, \ _handler) #pragma endregion // EventRegistrationToken RAII wrapper } // namespace wil #if (NTDDI_VERSION >= NTDDI_WINBLUE) /// @cond template <> struct ABI::Windows::Foundation::IAsyncOperation : ABI::Windows::Foundation::IAsyncOperation_impl { static const wchar_t* z_get_rc_name_impl() { return L"IAsyncOperation"; } }; template struct ABI::Windows::Foundation::IAsyncOperationWithProgress : ABI::Windows::Foundation::IAsyncOperationWithProgress_impl { static const wchar_t* z_get_rc_name_impl() { return L"IAsyncOperationWithProgress"; } }; template struct ABI::Windows::Foundation::IAsyncOperation*> : ABI::Windows::Foundation::IAsyncOperation_impl*> { static const wchar_t* z_get_rc_name_impl() { return L"IAsyncOperation*>"; } }; template struct ABI::Windows::Foundation::IAsyncOperationWithProgress*, P> : ABI::Windows::Foundation::IAsyncOperationWithProgress_impl*, P> { static const wchar_t* z_get_rc_name_impl() { return L"IAsyncOperationWithProgress*,P>"; } }; template struct ABI::Windows::Foundation::IAsyncOperation*> : ABI::Windows::Foundation::IAsyncOperation_impl*> { static const wchar_t* z_get_rc_name_impl() { return L"IAsyncOperation*>"; } }; template struct ABI::Windows::Foundation::IAsyncOperationWithProgress*, Z> : ABI::Windows::Foundation::IAsyncOperationWithProgress_impl*, Z> { static const wchar_t* z_get_rc_name_impl() { return L"IAsyncOperationWithProgress*,Z>"; } }; template <> struct ABI::Windows::Foundation::IAsyncOperationCompletedHandler : ABI::Windows::Foundation::IAsyncOperationCompletedHandler_impl { static const wchar_t* z_get_rc_name_impl() { return L"IAsyncOperationCompletedHandler"; } }; template struct ABI::Windows::Foundation::IAsyncOperationWithProgressCompletedHandler : ABI::Windows::Foundation::IAsyncOperationWithProgressCompletedHandler_impl { static const wchar_t* z_get_rc_name_impl() { return L"IAsyncOperationWithProgressCompletedHandler"; } }; template struct ABI::Windows::Foundation::IAsyncOperationCompletedHandler*> : ABI::Windows::Foundation::IAsyncOperationCompletedHandler_impl*> { static const wchar_t* z_get_rc_name_impl() { return L"IAsyncOperationCompletedHandler*>"; } }; template struct ABI::Windows::Foundation::IAsyncOperationWithProgressCompletedHandler*, P> : ABI::Windows::Foundation::IAsyncOperationWithProgressCompletedHandler_impl*, P> { static const wchar_t* z_get_rc_name_impl() { return L"IAsyncOperationWithProgressCompletedHandler*,P>"; } }; template struct ABI::Windows::Foundation::IAsyncOperationCompletedHandler*> : ABI::Windows::Foundation::IAsyncOperationCompletedHandler_impl*> { static const wchar_t* z_get_rc_name_impl() { return L"IAsyncOperationCompletedHandler*>"; } }; template struct ABI::Windows::Foundation::IAsyncOperationWithProgressCompletedHandler*, Z> : ABI::Windows::Foundation::IAsyncOperationWithProgressCompletedHandler_impl*, Z> { static const wchar_t* z_get_rc_name_impl() { return L"IAsyncOperationWithProgressCompletedHandler*,Z>"; } }; /// @endcond #endif // NTDDI_VERSION >= NTDDI_WINBLUE #if !defined(MIDL_NS_PREFIX) && !defined(____x_ABI_CWindows_CFoundation_CIClosable_FWD_DEFINED__) // Internal .idl files use the namespace without the ABI prefix. Macro out ABI for that case #pragma pop_macro("ABI") #endif #if __WI_HAS_STD_LESS namespace std { //! Specialization of `std::less` for `Microsoft::WRL::Wrappers::HString` that uses `hstring_less` for the //! comparison function object. template <> struct less : public wil::hstring_less { }; //! Specialization of `std::less` for `wil::unique_hstring` that uses `hstring_less` for the comparison function //! object. template <> struct less : public wil::hstring_less { }; } // namespace std #endif #endif // __WIL_WINRT_INCLUDED