//********************************************************* // // 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. // //********************************************************* #ifndef __WIL_CPPWINRT_HELPERS_DEFINED #define __WIL_CPPWINRT_HELPERS_DEFINED /// @cond namespace wil::details { struct dispatcher_RunAsync { template static void Schedule(Dispatcher const& dispatcher, Args&&... args) { dispatcher.RunAsync(std::forward(args)...); } }; struct dispatcher_TryEnqueue { template static void Schedule(Dispatcher const& dispatcher, Args&&... args) { dispatcher.TryEnqueue(std::forward(args)...); } }; template struct dispatcher_traits; } #if defined(_RESUMABLE_FUNCTIONS_SUPPORTED) #include namespace wil::details { template using coroutine_handle = std::experimental::coroutine_handle; } #elif defined(__cpp_lib_coroutine) && (__cpp_lib_coroutine >= 201902L) #include namespace wil::details { template using coroutine_handle = std::coroutine_handle; } #endif /// @endcond #if defined(_RESUMABLE_FUNCTIONS_SUPPORTED) || (defined(__cpp_lib_coroutine) && (__cpp_lib_coroutine >= 201902L)) /// @cond namespace wil::details { struct dispatched_handler_state { details::coroutine_handle<> handle{}; bool orphaned = false; }; struct dispatcher_handler { dispatcher_handler(dispatched_handler_state* state) : m_state(state) { } dispatcher_handler(dispatcher_handler&& other) noexcept : m_state(std::exchange(other.m_state, {})) {} ~dispatcher_handler() { if (m_state && m_state->handle) { m_state->orphaned = true; Complete(); } } void operator()() { Complete(); } void Complete() { auto state = std::exchange(m_state, nullptr); std::exchange(state->handle, {}).resume(); } dispatched_handler_state* m_state; }; } /// @endcond namespace wil { //! Resumes coroutine execution on the thread associated with the dispatcher, or throws //! an exception (from an arbitrary thread) if unable. Supported dispatchers are //! Windows.System.DispatcherQueue, Microsoft.System.DispatcherQueue, //! Microsoft.UI.Dispatching.DispatcherQueue, and Windows.UI.Core.CoreDispatcher, //! but you must include the corresponding header before including //! wil\cppwinrt_helpers.h. It is okay to include wil\cppwinrt_helpers.h multiple times: //! support will be enabled for any winrt/Namespace.h headers that were included since //! the previous inclusion of wil\cppwinrt_headers.h. template [[nodiscard]] auto resume_foreground(Dispatcher const& dispatcher, typename details::dispatcher_traits::Priority priority = details::dispatcher_traits::Priority::Normal) { using Traits = details::dispatcher_traits; using Priority = typename Traits::Priority; using Handler = typename Traits::Handler; struct awaitable { awaitable(Dispatcher const& dispatcher, Priority priority) noexcept : m_dispatcher(dispatcher), m_priority(priority) { } bool await_ready() const noexcept { return false; } void await_suspend(details::coroutine_handle<> handle) { m_state.handle = handle; Handler handler{ details::dispatcher_handler(&m_state) }; try { // The return value of Schedule is not reliable. Use the dispatcher_handler destructor // to detect whether the work item failed to run. Traits::Scheduler::Schedule(m_dispatcher, m_priority, handler); } catch (...) { m_state.handle = nullptr; // the exception will resume the coroutine, so the handler shouldn't do it throw; } } void await_resume() const { if (m_state.orphaned) { throw winrt::hresult_error(static_cast(0x800701ab)); // HRESULT_FROM_WIN32(ERROR_NO_TASK_QUEUE) } } private: Dispatcher const& m_dispatcher; Priority const m_priority; details::dispatched_handler_state m_state; }; return awaitable{ dispatcher, priority }; } } #endif // Coroutines are supported #endif // __WIL_CPPWINRT_HELPERS_DEFINED /// @cond #if defined(WINRT_Windows_UI_Core_H) && !defined(__WIL_CPPWINRT_WINDOWS_UI_CORE_HELPERS) #define __WIL_CPPWINRT_WINDOWS_UI_CORE_HELPERS namespace wil::details { template<> struct dispatcher_traits { using Priority = winrt::Windows::UI::Core::CoreDispatcherPriority; using Handler = winrt::Windows::UI::Core::DispatchedHandler; using Scheduler = dispatcher_RunAsync; }; } #endif // __WIL_CPPWINRT_WINDOWS_UI_CORE_HELPERS #if defined(WINRT_Windows_System_H) && !defined(__WIL_CPPWINRT_WINDOWS_SYSTEM_HELPERS) #define __WIL_CPPWINRT_WINDOWS_SYSTEM_HELPERS namespace wil::details { template<> struct dispatcher_traits { using Priority = winrt::Windows::System::DispatcherQueuePriority; using Handler = winrt::Windows::System::DispatcherQueueHandler; using Scheduler = dispatcher_TryEnqueue; }; } #endif // __WIL_CPPWINRT_WINDOWS_SYSTEM_HELPERS #if defined(WINRT_Microsoft_System_H) && !defined(__WIL_CPPWINRT_MICROSOFT_SYSTEM_HELPERS) #define __WIL_CPPWINRT_MICROSOFT_SYSTEM_HELPERS namespace wil::details { template<> struct dispatcher_traits { using Priority = winrt::Microsoft::System::DispatcherQueuePriority; using Handler = winrt::Microsoft::System::DispatcherQueueHandler; using Scheduler = dispatcher_TryEnqueue; }; } #endif // __WIL_CPPWINRT_MICROSOFT_SYSTEM_HELPERS #if defined(WINRT_Microsoft_UI_Dispatching_H) && !defined(__WIL_CPPWINRT_MICROSOFT_UI_DISPATCHING_HELPERS) #define __WIL_CPPWINRT_MICROSOFT_UI_DISPATCHING_HELPERS namespace wil::details { template<> struct dispatcher_traits { using Priority = winrt::Microsoft::UI::Dispatching::DispatcherQueuePriority; using Handler = winrt::Microsoft::UI::Dispatching::DispatcherQueueHandler; using Scheduler = dispatcher_TryEnqueue; }; } #endif // __WIL_CPPWINRT_MICROSOFT_UI_DISPATCHING_HELPERS /// @endcond #if defined(WINRT_Windows_Foundation_Collections_H) && !defined(__WIL_CPPWINRT_WINDOWS_FOUNDATION_COLLECTION_HELPERS) #define __WIL_CPPWINRT_WINDOWS_FOUNDATION_COLLECTION_HELPERS namespace wil { /// @cond namespace details { template struct is_winrt_vector_like { private: template ().GetMany(std::declval().Size(), winrt::array_view().GetAt(0))>{}))> static constexpr bool get_value(int) { return true; } template static constexpr bool get_value(...) { return false; } public: static constexpr bool value = get_value(0); }; template struct is_winrt_iterator_like { private: template ().GetMany(winrt::array_view().Current())>{}))> static constexpr bool get_value(int) { return true; } template static constexpr bool get_value(...) { return false; } public: static constexpr bool value = get_value(0); }; template constexpr T empty() noexcept { if constexpr (std::is_base_of_v) { return nullptr; } else { return {}; } } } /// @endcond /** Converts C++ / WinRT vectors, iterators, and iterables to std::vector by requesting the collection's data in bulk. This can be more efficient in terms of IPC cost than iteratively processing the collection. ~~~ winrt::IVector collection = GetCollection(); std::vector allData = wil::to_vector(collection); // read all data from collection for (winrt::hstring const& item : allData) { // use item } ~~~ Can be used for IVector, IVectorView, IIterable, IIterator, and any type or interface that C++/WinRT projects those interfaces for (PropertySet, IMap, etc.) Iterable-only types fetch content in units of 64. When used with an iterator, the returned vector contains the iterator's current position and any others after it. */ template auto to_vector(TSrc const& src) { if constexpr (details::is_winrt_vector_like::value) { using T = decltype(src.GetAt(0)); std::vector result; if (auto expected = src.Size()) { result.resize(expected + 1, details::empty()); auto actual = src.GetMany(0, result); if (actual > expected) { throw winrt::hresult_changed_state(); } result.resize(actual); } return result; } else if constexpr (details::is_winrt_iterator_like::value) { using T = decltype(src.Current()); std::vector result; constexpr uint32_t chunkSize = 64; while (true) { auto const lastSize = result.size(); result.resize(lastSize + chunkSize, details::empty()); auto fetched = src.GetMany({result.data() + lastSize, result.data() + lastSize + chunkSize }); if (fetched < chunkSize) { result.resize(lastSize + fetched); break; } } return result; } else { return to_vector(src.First()); } } } #endif #if defined(WINRT_Windows_UI_H) && defined(_WINDOWS_UI_INTEROP_H_) && !defined(__WIL_CPPWINRT_WINDOWS_UI_INTEROP_HELPERS) #define __WIL_CPPWINRT_WINDOWS_UI_INTEROP_HELPERS #if !defined(____x_ABI_CWindows_CFoundation_CIClosable_FWD_DEFINED__) && !defined(MIDL_NS_PREFIX) #pragma push_macro("ABI") #undef ABI #define ABI #endif namespace wil { #if defined(NTDDI_VERSION) && (NTDDI_VERSION >= NTDDI_WIN10_CU) //! The following methods require that you include both //! before including wil/cppwinrt_helpers.h, and that NTDDI_VERSION //! is at least NTDDI_WIN10_CU. It is okay to include wil\cppwinrt_helpers.h multiple times: //! support will be enabled for any headers that were included since the previous inclusion //! of wil\cppwinrt_headers.h. inline winrt::Windows::UI::WindowId GetWindowIdFromWindow(HWND hwnd) { ABI::Windows::UI::WindowId abiWindowId; winrt::check_hresult(::GetWindowIdFromWindow(hwnd, &abiWindowId)); return winrt::Windows::UI::WindowId{ abiWindowId.Value }; } inline HWND GetWindowFromWindowId(winrt::Windows::UI::WindowId windowId) { HWND hwnd; winrt::check_hresult(::GetWindowFromWindowId({ windowId.Value }, &hwnd)); return hwnd; } #endif /*defined(NTDDI_VERSION) && (NTDDI_VERSION >= NTDDI_WIN10_CU)*/ } #if !defined(____x_ABI_CWindows_CFoundation_CIClosable_FWD_DEFINED__) && !defined(MIDL_NS_PREFIX) #pragma pop_macro("ABI") #endif #endif // __WIL_CPPWINRT_WINDOWS_UI_INTEROP_HELPERS