Chris@16
|
1 //
|
Chris@16
|
2 // detail/winrt_async_manager.hpp
|
Chris@16
|
3 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
Chris@16
|
4 //
|
Chris@101
|
5 // Copyright (c) 2003-2015 Christopher M. Kohlhoff (chris at kohlhoff dot com)
|
Chris@16
|
6 //
|
Chris@16
|
7 // Distributed under the Boost Software License, Version 1.0. (See accompanying
|
Chris@16
|
8 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
Chris@16
|
9 //
|
Chris@16
|
10
|
Chris@16
|
11 #ifndef BOOST_ASIO_DETAIL_WINRT_ASYNC_MANAGER_HPP
|
Chris@16
|
12 #define BOOST_ASIO_DETAIL_WINRT_ASYNC_MANAGER_HPP
|
Chris@16
|
13
|
Chris@16
|
14 #if defined(_MSC_VER) && (_MSC_VER >= 1200)
|
Chris@16
|
15 # pragma once
|
Chris@16
|
16 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
|
Chris@16
|
17
|
Chris@16
|
18 #include <boost/asio/detail/config.hpp>
|
Chris@16
|
19
|
Chris@16
|
20 #if defined(BOOST_ASIO_WINDOWS_RUNTIME)
|
Chris@16
|
21
|
Chris@16
|
22 #include <future>
|
Chris@16
|
23 #include <boost/asio/detail/atomic_count.hpp>
|
Chris@16
|
24 #include <boost/asio/detail/winrt_async_op.hpp>
|
Chris@16
|
25 #include <boost/asio/error.hpp>
|
Chris@16
|
26 #include <boost/asio/io_service.hpp>
|
Chris@16
|
27
|
Chris@16
|
28 #include <boost/asio/detail/push_options.hpp>
|
Chris@16
|
29
|
Chris@16
|
30 namespace boost {
|
Chris@16
|
31 namespace asio {
|
Chris@16
|
32 namespace detail {
|
Chris@16
|
33
|
Chris@16
|
34 class winrt_async_manager
|
Chris@16
|
35 : public boost::asio::detail::service_base<winrt_async_manager>
|
Chris@16
|
36 {
|
Chris@16
|
37 public:
|
Chris@16
|
38 // Constructor.
|
Chris@16
|
39 winrt_async_manager(boost::asio::io_service& io_service)
|
Chris@16
|
40 : boost::asio::detail::service_base<winrt_async_manager>(io_service),
|
Chris@16
|
41 io_service_(use_service<io_service_impl>(io_service)),
|
Chris@16
|
42 outstanding_ops_(1)
|
Chris@16
|
43 {
|
Chris@16
|
44 }
|
Chris@16
|
45
|
Chris@16
|
46 // Destructor.
|
Chris@16
|
47 ~winrt_async_manager()
|
Chris@16
|
48 {
|
Chris@16
|
49 }
|
Chris@16
|
50
|
Chris@16
|
51 // Destroy all user-defined handler objects owned by the service.
|
Chris@16
|
52 void shutdown_service()
|
Chris@16
|
53 {
|
Chris@16
|
54 if (--outstanding_ops_ > 0)
|
Chris@16
|
55 {
|
Chris@16
|
56 // Block until last operation is complete.
|
Chris@16
|
57 std::future<void> f = promise_.get_future();
|
Chris@16
|
58 f.wait();
|
Chris@16
|
59 }
|
Chris@16
|
60 }
|
Chris@16
|
61
|
Chris@16
|
62 void sync(Windows::Foundation::IAsyncAction^ action,
|
Chris@16
|
63 boost::system::error_code& ec)
|
Chris@16
|
64 {
|
Chris@16
|
65 using namespace Windows::Foundation;
|
Chris@16
|
66 using Windows::Foundation::AsyncStatus;
|
Chris@16
|
67
|
Chris@16
|
68 auto promise = std::make_shared<std::promise<boost::system::error_code>>();
|
Chris@16
|
69 auto future = promise->get_future();
|
Chris@16
|
70
|
Chris@16
|
71 action->Completed = ref new AsyncActionCompletedHandler(
|
Chris@16
|
72 [promise](IAsyncAction^ action, AsyncStatus status)
|
Chris@16
|
73 {
|
Chris@16
|
74 switch (status)
|
Chris@16
|
75 {
|
Chris@16
|
76 case AsyncStatus::Canceled:
|
Chris@16
|
77 promise->set_value(boost::asio::error::operation_aborted);
|
Chris@16
|
78 break;
|
Chris@16
|
79 case AsyncStatus::Error:
|
Chris@16
|
80 case AsyncStatus::Completed:
|
Chris@16
|
81 default:
|
Chris@16
|
82 boost::system::error_code ec(
|
Chris@16
|
83 action->ErrorCode.Value,
|
Chris@16
|
84 boost::system::system_category());
|
Chris@16
|
85 promise->set_value(ec);
|
Chris@16
|
86 break;
|
Chris@16
|
87 }
|
Chris@16
|
88 });
|
Chris@16
|
89
|
Chris@16
|
90 ec = future.get();
|
Chris@16
|
91 }
|
Chris@16
|
92
|
Chris@16
|
93 template <typename TResult>
|
Chris@16
|
94 TResult sync(Windows::Foundation::IAsyncOperation<TResult>^ operation,
|
Chris@16
|
95 boost::system::error_code& ec)
|
Chris@16
|
96 {
|
Chris@16
|
97 using namespace Windows::Foundation;
|
Chris@16
|
98 using Windows::Foundation::AsyncStatus;
|
Chris@16
|
99
|
Chris@16
|
100 auto promise = std::make_shared<std::promise<boost::system::error_code>>();
|
Chris@16
|
101 auto future = promise->get_future();
|
Chris@16
|
102
|
Chris@16
|
103 operation->Completed = ref new AsyncOperationCompletedHandler<TResult>(
|
Chris@16
|
104 [promise](IAsyncOperation<TResult>^ operation, AsyncStatus status)
|
Chris@16
|
105 {
|
Chris@16
|
106 switch (status)
|
Chris@16
|
107 {
|
Chris@16
|
108 case AsyncStatus::Canceled:
|
Chris@16
|
109 promise->set_value(boost::asio::error::operation_aborted);
|
Chris@16
|
110 break;
|
Chris@16
|
111 case AsyncStatus::Error:
|
Chris@16
|
112 case AsyncStatus::Completed:
|
Chris@16
|
113 default:
|
Chris@16
|
114 boost::system::error_code ec(
|
Chris@16
|
115 operation->ErrorCode.Value,
|
Chris@16
|
116 boost::system::system_category());
|
Chris@16
|
117 promise->set_value(ec);
|
Chris@16
|
118 break;
|
Chris@16
|
119 }
|
Chris@16
|
120 });
|
Chris@16
|
121
|
Chris@16
|
122 ec = future.get();
|
Chris@16
|
123 return operation->GetResults();
|
Chris@16
|
124 }
|
Chris@16
|
125
|
Chris@16
|
126 template <typename TResult, typename TProgress>
|
Chris@16
|
127 TResult sync(
|
Chris@16
|
128 Windows::Foundation::IAsyncOperationWithProgress<
|
Chris@16
|
129 TResult, TProgress>^ operation,
|
Chris@16
|
130 boost::system::error_code& ec)
|
Chris@16
|
131 {
|
Chris@16
|
132 using namespace Windows::Foundation;
|
Chris@16
|
133 using Windows::Foundation::AsyncStatus;
|
Chris@16
|
134
|
Chris@16
|
135 auto promise = std::make_shared<std::promise<boost::system::error_code>>();
|
Chris@16
|
136 auto future = promise->get_future();
|
Chris@16
|
137
|
Chris@16
|
138 operation->Completed
|
Chris@16
|
139 = ref new AsyncOperationWithProgressCompletedHandler<TResult, TProgress>(
|
Chris@16
|
140 [promise](IAsyncOperationWithProgress<TResult, TProgress>^ operation,
|
Chris@16
|
141 AsyncStatus status)
|
Chris@16
|
142 {
|
Chris@16
|
143 switch (status)
|
Chris@16
|
144 {
|
Chris@16
|
145 case AsyncStatus::Canceled:
|
Chris@16
|
146 promise->set_value(boost::asio::error::operation_aborted);
|
Chris@16
|
147 break;
|
Chris@16
|
148 case AsyncStatus::Started:
|
Chris@16
|
149 break;
|
Chris@16
|
150 case AsyncStatus::Error:
|
Chris@16
|
151 case AsyncStatus::Completed:
|
Chris@16
|
152 default:
|
Chris@16
|
153 boost::system::error_code ec(
|
Chris@16
|
154 operation->ErrorCode.Value,
|
Chris@16
|
155 boost::system::system_category());
|
Chris@16
|
156 promise->set_value(ec);
|
Chris@16
|
157 break;
|
Chris@16
|
158 }
|
Chris@16
|
159 });
|
Chris@16
|
160
|
Chris@16
|
161 ec = future.get();
|
Chris@16
|
162 return operation->GetResults();
|
Chris@16
|
163 }
|
Chris@16
|
164
|
Chris@16
|
165 void async(Windows::Foundation::IAsyncAction^ action,
|
Chris@16
|
166 winrt_async_op<void>* handler)
|
Chris@16
|
167 {
|
Chris@16
|
168 using namespace Windows::Foundation;
|
Chris@16
|
169 using Windows::Foundation::AsyncStatus;
|
Chris@16
|
170
|
Chris@16
|
171 auto on_completed = ref new AsyncActionCompletedHandler(
|
Chris@16
|
172 [this, handler](IAsyncAction^ action, AsyncStatus status)
|
Chris@16
|
173 {
|
Chris@16
|
174 switch (status)
|
Chris@16
|
175 {
|
Chris@16
|
176 case AsyncStatus::Canceled:
|
Chris@16
|
177 handler->ec_ = boost::asio::error::operation_aborted;
|
Chris@16
|
178 break;
|
Chris@16
|
179 case AsyncStatus::Started:
|
Chris@16
|
180 return;
|
Chris@16
|
181 case AsyncStatus::Completed:
|
Chris@16
|
182 case AsyncStatus::Error:
|
Chris@16
|
183 default:
|
Chris@16
|
184 handler->ec_ = boost::system::error_code(
|
Chris@16
|
185 action->ErrorCode.Value,
|
Chris@16
|
186 boost::system::system_category());
|
Chris@16
|
187 break;
|
Chris@16
|
188 }
|
Chris@16
|
189 io_service_.post_deferred_completion(handler);
|
Chris@16
|
190 if (--outstanding_ops_ == 0)
|
Chris@16
|
191 promise_.set_value();
|
Chris@16
|
192 });
|
Chris@16
|
193
|
Chris@16
|
194 io_service_.work_started();
|
Chris@16
|
195 ++outstanding_ops_;
|
Chris@16
|
196 action->Completed = on_completed;
|
Chris@16
|
197 }
|
Chris@16
|
198
|
Chris@16
|
199 template <typename TResult>
|
Chris@16
|
200 void async(Windows::Foundation::IAsyncOperation<TResult>^ operation,
|
Chris@16
|
201 winrt_async_op<TResult>* handler)
|
Chris@16
|
202 {
|
Chris@16
|
203 using namespace Windows::Foundation;
|
Chris@16
|
204 using Windows::Foundation::AsyncStatus;
|
Chris@16
|
205
|
Chris@16
|
206 auto on_completed = ref new AsyncOperationCompletedHandler<TResult>(
|
Chris@16
|
207 [this, handler](IAsyncOperation<TResult>^ operation, AsyncStatus status)
|
Chris@16
|
208 {
|
Chris@16
|
209 switch (status)
|
Chris@16
|
210 {
|
Chris@16
|
211 case AsyncStatus::Canceled:
|
Chris@16
|
212 handler->ec_ = boost::asio::error::operation_aborted;
|
Chris@16
|
213 break;
|
Chris@16
|
214 case AsyncStatus::Started:
|
Chris@16
|
215 return;
|
Chris@16
|
216 case AsyncStatus::Completed:
|
Chris@16
|
217 handler->result_ = operation->GetResults();
|
Chris@16
|
218 // Fall through.
|
Chris@16
|
219 case AsyncStatus::Error:
|
Chris@16
|
220 default:
|
Chris@16
|
221 handler->ec_ = boost::system::error_code(
|
Chris@16
|
222 operation->ErrorCode.Value,
|
Chris@16
|
223 boost::system::system_category());
|
Chris@16
|
224 break;
|
Chris@16
|
225 }
|
Chris@16
|
226 io_service_.post_deferred_completion(handler);
|
Chris@16
|
227 if (--outstanding_ops_ == 0)
|
Chris@16
|
228 promise_.set_value();
|
Chris@16
|
229 });
|
Chris@16
|
230
|
Chris@16
|
231 io_service_.work_started();
|
Chris@16
|
232 ++outstanding_ops_;
|
Chris@16
|
233 operation->Completed = on_completed;
|
Chris@16
|
234 }
|
Chris@16
|
235
|
Chris@16
|
236 template <typename TResult, typename TProgress>
|
Chris@16
|
237 void async(
|
Chris@16
|
238 Windows::Foundation::IAsyncOperationWithProgress<
|
Chris@16
|
239 TResult, TProgress>^ operation,
|
Chris@16
|
240 winrt_async_op<TResult>* handler)
|
Chris@16
|
241 {
|
Chris@16
|
242 using namespace Windows::Foundation;
|
Chris@16
|
243 using Windows::Foundation::AsyncStatus;
|
Chris@16
|
244
|
Chris@16
|
245 auto on_completed
|
Chris@16
|
246 = ref new AsyncOperationWithProgressCompletedHandler<TResult, TProgress>(
|
Chris@16
|
247 [this, handler](IAsyncOperationWithProgress<
|
Chris@16
|
248 TResult, TProgress>^ operation, AsyncStatus status)
|
Chris@16
|
249 {
|
Chris@16
|
250 switch (status)
|
Chris@16
|
251 {
|
Chris@16
|
252 case AsyncStatus::Canceled:
|
Chris@16
|
253 handler->ec_ = boost::asio::error::operation_aborted;
|
Chris@16
|
254 break;
|
Chris@16
|
255 case AsyncStatus::Started:
|
Chris@16
|
256 return;
|
Chris@16
|
257 case AsyncStatus::Completed:
|
Chris@16
|
258 handler->result_ = operation->GetResults();
|
Chris@16
|
259 // Fall through.
|
Chris@16
|
260 case AsyncStatus::Error:
|
Chris@16
|
261 default:
|
Chris@16
|
262 handler->ec_ = boost::system::error_code(
|
Chris@16
|
263 operation->ErrorCode.Value,
|
Chris@16
|
264 boost::system::system_category());
|
Chris@16
|
265 break;
|
Chris@16
|
266 }
|
Chris@16
|
267 io_service_.post_deferred_completion(handler);
|
Chris@16
|
268 if (--outstanding_ops_ == 0)
|
Chris@16
|
269 promise_.set_value();
|
Chris@16
|
270 });
|
Chris@16
|
271
|
Chris@16
|
272 io_service_.work_started();
|
Chris@16
|
273 ++outstanding_ops_;
|
Chris@16
|
274 operation->Completed = on_completed;
|
Chris@16
|
275 }
|
Chris@16
|
276
|
Chris@16
|
277 private:
|
Chris@16
|
278 // The io_service implementation used to post completed handlers.
|
Chris@16
|
279 io_service_impl& io_service_;
|
Chris@16
|
280
|
Chris@16
|
281 // Count of outstanding operations.
|
Chris@16
|
282 atomic_count outstanding_ops_;
|
Chris@16
|
283
|
Chris@16
|
284 // Used to keep wait for outstanding operations to complete.
|
Chris@16
|
285 std::promise<void> promise_;
|
Chris@16
|
286 };
|
Chris@16
|
287
|
Chris@16
|
288 } // namespace detail
|
Chris@16
|
289 } // namespace asio
|
Chris@16
|
290 } // namespace boost
|
Chris@16
|
291
|
Chris@16
|
292 #include <boost/asio/detail/pop_options.hpp>
|
Chris@16
|
293
|
Chris@16
|
294 #endif // defined(BOOST_ASIO_WINDOWS_RUNTIME)
|
Chris@16
|
295
|
Chris@16
|
296 #endif // BOOST_ASIO_DETAIL_WINRT_ASYNC_MANAGER_HPP
|