{"id":103968,"date":"2020-07-08T07:00:00","date_gmt":"2020-07-08T14:00:00","guid":{"rendered":"https:\/\/devblogs.microsoft.com\/oldnewthing\/?p=103968"},"modified":"2020-07-08T08:18:46","modified_gmt":"2020-07-08T15:18:46","slug":"20200708-00","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20200708-00\/?p=103968","title":{"rendered":"Cancelling a Windows Runtime asynchronous operation, part 6: C++\/WinRT-generated asynchronous operations"},"content":{"rendered":"<p>Last time, we learned that <a href=\"https:\/\/devblogs.microsoft.com\/oldnewthing\/20200707-00\/?p=103960\"> C++\/WinRT defers to the underlying asynchronous operation to report the cancellation in whatever way it sees fit<\/a>. Today, we&#8217;ll look at the case that the asynchronous operation was generated by the C++\/WinRT library.<\/p>\n<p>When you invoke the <code>Cancel()<\/code> on a C++\/WinRT asynchronous operation, this is the code that runs:<\/p>\n<pre>struct promise_base : ...\r\n{\r\n    ...\r\n\r\n    void Cancel() noexcept\r\n    {\r\n        winrt::delegate&lt;&gt; cancel;\r\n        {\r\n            slim_lock_guard const guard(m_lock);\r\n            if (m_status == AsyncStatus::Started)\r\n            {\r\n                <span style=\"color: blue;\">m_status = AsyncStatus::Canceled;<\/span>\r\n                cancel = std::move(m_cancel);\r\n            }\r\n        }\r\n        if (cancel)\r\n        {\r\n            cancel();\r\n        }\r\n    }\r\n};\r\n<\/pre>\n<p>The promise transitions into the <code>Canceled<\/code>, and if the coroutine had registered a cancellation callback, it is invoked.<\/p>\n<p>Whenever the coroutine associated with the promise performs a <code>co_await<\/code>, the <code>await_transform<\/code> kicks in (sorry, I haven&#8217;t explained this yet, but trust me), and that&#8217;s where the C++\/WinRT library gets a chance to abandon the operation:<\/p>\n<pre>template &lt;typename Expression&gt;\r\nExpression&amp;&amp; await_transform(Expression&amp;&amp; expression)\r\n{\r\n    <span style=\"color: blue;\">if (Status() == AsyncStatus::Canceled)\r\n    {\r\n        throw winrt::hresult_canceled();\r\n    }<\/span>\r\n    return std::forward&lt;Expression&gt;(expression);\r\n}\r\n<\/pre>\n<p>The thrown <code>hresult_canceled<\/code> exception is captured into the operation for later rethrowing.<\/p>\n<p>The C++\/WinRT library also checks for cancellation when the coroutine runs to completion:<\/p>\n<pre>struct promise_type final : ...\r\n{\r\n    ...\r\n\r\n    void return_void()\r\n    {\r\n        ...\r\n        if (this-&gt;m_status == AsyncStatus::Started)\r\n        {\r\n            this-&gt;m_status = AsyncStatus::Completed;\r\n        }\r\n        else\r\n        {\r\n            WINRT_ASSERT(this-&gt;m_status == AsyncStatus::Canceled);\r\n            <span style=\"color: blue;\">this-&gt;m_exception = make_exception_ptr(winrt::hresult_canceled());<\/span>\r\n        }\r\n        ...\r\n    }\r\n};\r\n<\/pre>\n<p>If the operation has been cancelled, then we manufacture a fake <code>hresult_canceled<\/code> exception and save it in the <code>m_exception<\/code>.<\/p>\n<p>So we see that whether the operation&#8217;s cancellation is detected by <code>await_transform<\/code> or by <code>return_void<\/code> (or <code>return_value<\/code> for coroutines that produce a value), we end up with an <code>hresult_canceled<\/code> exception stashed in the operation.<\/p>\n<p>And it is this exception that comes back out when somebody asks for the result of the asynchronous activity:<\/p>\n<pre>struct promise_type final : ...\r\n{\r\n    ...\r\n\r\n    void GetResults()\r\n    {\r\n        ...\r\n        if (this-&gt;m_status == AsyncStatus::Completed)\r\n        {\r\n            return;\r\n        }\r\n        <span style=\"color: blue;\">this-&gt;rethrow_if_failed();<\/span>\r\n        ...\r\n    }\r\n\r\n    void rethrow_if_failed() const\r\n    {\r\n        if (m_status == AsyncStatus::Error || m_status == AsyncStatus::Canceled)\r\n        {\r\n            std::rethrow_exception(m_exception);\r\n        }\r\n    }\r\n};\r\n<\/pre>\n<p>If the operation was canceled, then we reach <code>rethrow_<wbr \/>if_<wbr \/>failed<\/code> which rethrows the captured exception, which we saw earlier is going to be an <code>hresult_<wbr \/>canceled<\/code>.<\/p>\n<p>But C++\/WinRT is not the only source of <code>IAsync\u00adAction<\/code> and <code>IAsync\u00adOperation<\/code> objects. Next time, we&#8217;ll look at another major source: WRL.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>It came from inside the building.<\/p>\n","protected":false},"author":1069,"featured_media":111744,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[1],"tags":[25],"class_list":["post-103968","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>It came from inside the building.<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/103968","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/users\/1069"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/comments?post=103968"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/103968\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/media\/111744"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/media?parent=103968"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=103968"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=103968"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}