@@ -38,19 +38,32 @@ namespace winrt::impl
3838 WINRT_ASSERT (!is_sta ());
3939 }
4040
41- template <typename Async >
42- void wait_for_completed (Async const & async, uint32_t const timeout )
41+ template <typename T, typename H >
42+ std::pair<T, H*> make_delegate_with_shared_state (H&& handler )
4343 {
44- void * event = check_pointer (WINRT_IMPL_CreateEventW (nullptr , true , false , nullptr ));
44+ auto d = make_delegate<T, H>(std::forward<H>(handler));
45+ return { std::move (d), reinterpret_cast <delegate<T, H>*>(get_abi (d)) };
46+ }
4547
46- // The delegate is a local to ensure that the event outlives the call to WaitForSingleObject.
47- async_completed_handler_t <Async> delegate = [event = handle (event)](auto && ...)
48+ template <typename Async>
49+ auto wait_for_completed (Async const & async, uint32_t const timeout)
50+ {
51+ struct shared_type
4852 {
49- WINRT_VERIFY (WINRT_IMPL_SetEvent (event.get ()));
53+ handle event{ check_pointer (WINRT_IMPL_CreateEventW (nullptr , true , false , nullptr )) };
54+ Windows::Foundation::AsyncStatus status{ Windows::Foundation::AsyncStatus::Started };
55+
56+ void operator ()(Async const &, Windows::Foundation::AsyncStatus operation_status) noexcept
57+ {
58+ status = operation_status;
59+ WINRT_VERIFY (WINRT_IMPL_SetEvent (event.get ()));
60+ }
5061 };
5162
63+ auto [delegate, shared] = make_delegate_with_shared_state<async_completed_handler_t <Async>>(shared_type{});
5264 async.Completed (delegate);
53- WINRT_IMPL_WaitForSingleObject (event, timeout);
65+ WINRT_IMPL_WaitForSingleObject (shared->event .get (), timeout);
66+ return shared->status ;
5467 }
5568
5669 template <typename Async>
@@ -59,19 +72,28 @@ namespace winrt::impl
5972 check_sta_blocking_wait ();
6073 auto const milliseconds = std::chrono::duration_cast<std::chrono::milliseconds>(timeout).count ();
6174 WINRT_ASSERT ((milliseconds >= 0 ) && (static_cast <uint64_t >(milliseconds) < 0xFFFFFFFFull )); // Within uint32_t range and not INFINITE
62- wait_for_completed (async, static_cast <uint32_t >(milliseconds));
63- return async.Status ();
75+ return wait_for_completed (async, static_cast <uint32_t >(milliseconds));
76+ }
77+
78+ inline void check_status_canceled (Windows::Foundation::AsyncStatus status)
79+ {
80+ if (status == Windows::Foundation::AsyncStatus::Canceled)
81+ {
82+ throw hresult_canceled ();
83+ }
6484 }
6585
6686 template <typename Async>
6787 auto wait_get (Async const & async)
6888 {
6989 check_sta_blocking_wait ();
7090
71- if (async.Status () == Windows::Foundation::AsyncStatus::Started)
91+ auto status = async.Status ();
92+ if (status == Windows::Foundation::AsyncStatus::Started)
7293 {
73- wait_for_completed (async, 0xFFFFFFFF ); // INFINITE
94+ status = wait_for_completed (async, 0xFFFFFFFF ); // INFINITE
7495 }
96+ check_status_canceled (status);
7597
7698 return async.GetResults ();
7799 }
@@ -90,7 +112,7 @@ namespace winrt::impl
90112 if (m_handle) Complete ();
91113 }
92114
93- void operator ()(Windows::Foundation::IAsyncInfo const &, Windows::Foundation::AsyncStatus )
115+ void operator ()()
94116 {
95117 Complete ();
96118 }
@@ -109,19 +131,25 @@ namespace winrt::impl
109131 struct await_adapter
110132 {
111133 Async const & async;
134+ Windows::Foundation::AsyncStatus status = Windows::Foundation::AsyncStatus::Started;
112135
113136 bool await_ready () const noexcept
114137 {
115138 return false ;
116139 }
117140
118- void await_suspend (std::experimental::coroutine_handle<> handle) const
141+ void await_suspend (std::experimental::coroutine_handle<> handle)
119142 {
120- async.Completed (disconnect_aware_handler{ handle });
143+ async.Completed ([this , handler = disconnect_aware_handler{ handle }](auto &&, auto operation_status) mutable
144+ {
145+ status = operation_status;
146+ handler ();
147+ });
121148 }
122149
123150 auto await_resume () const
124151 {
152+ check_status_canceled (status);
125153 return async.GetResults ();
126154 }
127155 };
@@ -691,28 +719,33 @@ WINRT_EXPORT namespace winrt
691719 struct shared_type
692720 {
693721 handle event{ check_pointer (WINRT_IMPL_CreateEventW (nullptr , true , false , nullptr )) };
722+ Windows::Foundation::AsyncStatus status{ Windows::Foundation::AsyncStatus::Started };
694723 T result;
724+
725+ void operator ()(T const & sender, Windows::Foundation::AsyncStatus operation_status) noexcept
726+ {
727+ auto sender_abi = *(impl::unknown_abi**)&sender;
728+
729+ if (nullptr == _InterlockedCompareExchangePointer (reinterpret_cast <void **>(&result), sender_abi, nullptr ))
730+ {
731+ sender_abi->AddRef ();
732+ status = operation_status;
733+ WINRT_VERIFY (WINRT_IMPL_SetEvent (event.get ()));
734+ }
735+ }
695736 };
696737
697- auto shared = std::make_shared<shared_type>( );
738+ auto [delegate, shared] = impl::make_delegate_with_shared_state<impl:: async_completed_handler_t <T>>(shared_type{} );
698739
699740 auto completed = [&](T const & async)
700741 {
701- async.Completed ([shared](T const & sender, Windows::Foundation::AsyncStatus) noexcept
702- {
703- auto sender_abi = *(impl::unknown_abi**)&sender;
704-
705- if (nullptr == _InterlockedCompareExchangePointer (reinterpret_cast <void **>(&shared->result ), sender_abi, nullptr ))
706- {
707- sender_abi->AddRef ();
708- WINRT_VERIFY (WINRT_IMPL_SetEvent (shared->event .get ()));
709- }
710- });
742+ async.Completed (delegate);
711743 };
712744
713745 completed (first);
714746 (completed (rest), ...);
715747 co_await resume_on_signal (shared->event .get ());
748+ impl::check_status_canceled (shared->status );
716749 co_return shared->result .GetResults ();
717750 }
718751}
0 commit comments