{"id":109953,"date":"2024-07-03T07:00:00","date_gmt":"2024-07-03T14:00:00","guid":{"rendered":"https:\/\/devblogs.microsoft.com\/oldnewthing\/?p=109953"},"modified":"2024-06-24T09:10:03","modified_gmt":"2024-06-24T16:10:03","slug":"20240703-00","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20240703-00\/?p=109953","title":{"rendered":"How do I produce a Windows Runtime asynchronous activity from C++\/CX?"},"content":{"rendered":"<p>You might be working in a code base written in C++\/CX.<\/p>\n<p>First, I&#8217;m sorry.<\/p>\n<p>Second, maybe you need to produce an <code>IAsyncAction^<\/code> or one of its relatives. How do you do that?<\/p>\n<p>You <a href=\"https:\/\/learn.microsoft.com\/archive\/msdn-magazine\/2012\/february\/asynchronous-programming-asynchronous-programming-in-c-using-ppl\"> use the <code>Concurrency::<wbr \/>create_<wbr \/>async<\/code> method<\/a>.<\/p>\n<p>The <code>Concurrency::<wbr \/>create_<wbr \/>async<\/code> method studies its parameter and infers what kind of Windows Runtime asynchronous activity to produce based on the signature of the lambda.<\/p>\n<p>Given a lambda whose function call operator has the signature <code>R(Params...)<\/code>, the <code>create_<wbr \/>async<\/code> function returns the following Windows Runtime interface:<\/p>\n<table class=\"cp3\" style=\"border-collapse: collapse;\" border=\"1\" cellspacing=\"0\" cellpadding=\"3\">\n<tbody>\n<tr>\n<th rowspan=\"2\">\u00a0<\/th>\n<th colspan=\"2\">Params&#8230;<\/th>\n<\/tr>\n<tr>\n<td><code>()<\/code><br \/>\n<code>(cancellation_token)<\/code><\/td>\n<td><code>(progress_reporter&lt;P&gt;)<\/code><br \/>\n<code>(progress_reporter&lt;P&gt;, cancellation_token)<\/code><\/td>\n<\/tr>\n<tr>\n<td><code>R<\/code> = <code>void<\/code><br \/>\n<code>R<\/code> = <code>task&lt;void&gt;<\/code><\/td>\n<td><code>IAsyncAction^<\/code><\/td>\n<td><code>IAsyncActionWithProgress&lt;P&gt;^<\/code><\/td>\n<\/tr>\n<tr>\n<td><code>R<\/code> = <code>T<\/code><br \/>\n<code>R<\/code> = <code>task&lt;T&gt;<\/code><\/td>\n<td><code>IAsyncOperation&lt;T&gt;^<\/code><\/td>\n<td><code>IAsyncOperationWithProgress&lt;T, P&gt;^<\/code><\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>Inside the lambda, you can use the <code>progress_<wbr \/>reporter&lt;P&gt;<\/code> to produce progress reports, and you can use the optional <code>cancellation_<wbr \/>token<\/code> to detect whether the asynchronous activity has been canceled.<\/p>\n<p>Here&#8217;s the simplest case: An <code>IAsyncAction^<\/code> with no cancellation.<\/p>\n<pre>task&lt;Widget^&gt; GetWidgetAsync(String^);\r\ntask&lt;void&gt; EnableWidgetAsync(Widget^, bool);\r\n\r\n\/\/ Old school: Task chain\r\nIAsyncAction^ EnableWidgetByIdAsync(String^ id, bool enable)\r\n{\r\n    return create_async([=]()\r\n        -&gt; task&lt;void&gt; {\r\n        return GetWidgetAsync(id).then(\r\n        [=](Widget^ widget) {\r\n            return EnableWidgetAsync(widget, enable);\r\n        });\r\n    });\r\n}\r\n\r\n\/\/ New hotness: co_await\r\nIAsyncAction^ EnableWidgetByIdAsync(String^ id, bool enable)\r\n{\r\n    return create_async([=]()\r\n        -&gt; task&lt;void&gt; {\r\n        Widget^ widget = co_await GetWidgetAsync(id);\r\n        co_await EnableWidgetAsync(widget, enable);\r\n    });\r\n}\r\n<\/pre>\n<p>With cancellation but no progress:<\/p>\n<pre>void ThrowIfCanceled(cancellation_token const&amp; cancel)\r\n{\r\n    if (cancel.is_canceled()) cancel_current_task();\r\n}\r\n\r\n\/\/ Old school: Task chain\r\nIAsyncAction^ EnableWidgetByIdAsync(String^ id, bool enable)\r\n{\r\n    return create_async([=](<span style=\"border: solid 1px currentcolor;\">cancellation_token cancel<\/span>)\r\n        -&gt; task&lt;void&gt; {\r\n        return GetWidgetAsync(id).then(\r\n        [=](Widget^ widget) { \/\/ explicitly: [enable, <span style=\"border: solid 1px currentcolor;\">cancel<\/span>]\r\n            <span style=\"border: solid 1px currentcolor;\">ThrowIfCanceled(cancel);<\/span>\r\n            return EnableWidgetAsync(widget, enable);\r\n        });\r\n    });\r\n}\r\n\r\n\/\/ New hotness: co_await\r\nIAsyncAction^ EnableWidgetByIdAsync(String^ id, bool enable)\r\n{\r\n    return create_async([=](<span style=\"border: solid 1px currentcolor;\">cancellation_token cancel<\/span>)\r\n        -&gt; task&lt;void&gt; {\r\n        Widget^ widget = co_await GetWidgetAsync(id);\r\n        <span style=\"border: solid 1px currentcolor;\">ThrowIfCanceled(cancel);<\/span>\r\n        co_await EnableWidgetAsync(widget, enable);\r\n    });\r\n}\r\n<\/pre>\n<p>With progress but no cancellation:<\/p>\n<pre>\/\/ Old school: Task chain\r\nIAsyncActionWithProgress&lt;int&gt;^\r\n    EnableWidgetByIdAsync(String^ id, bool enable)\r\n{\r\n    return create_async([=](<span style=\"border: solid 1px currentcolor;\">progress_reporter&lt;int&gt; progress<\/span>)\r\n        -&gt; task&lt;void&gt; {\r\n        <span style=\"border: solid 1px currentcolor;\">progress.report(0);<\/span>\r\n        return GetWidgetAsync(id).then(\r\n        [=](Widget^ widget) { \/\/ explicitly: [enable, <span style=\"border: solid 1px currentcolor;\">progress<\/span>]\r\n            <span style=\"border: solid 1px currentcolor;\">progress.report(1);<\/span>\r\n            return EnableWidgetAsync(widget, enable);\r\n        });\r\n    });\r\n}\r\n\r\n\/\/ New hotness: co_await\r\nIAsyncAction^ EnableWidgetByIdAsync(String^ id, bool enable)\r\n{\r\n    return create_async([=](<span style=\"border: solid 1px currentcolor;\">progress_reporter&lt;int&gt; progress<\/span>))\r\n        -&gt; task&lt;void&gt; {\r\n        <span style=\"border: solid 1px currentcolor;\">progress.report(0);<\/span>\r\n        Widget^ widget = co_await GetWidgetAsync(id);\r\n        <span style=\"border: solid 1px currentcolor;\">progress.report(1);<\/span>\r\n        co_await EnableWidgetAsync(widget, enable);\r\n    });\r\n}\r\n<\/pre>\n<p>And with both progress and cancellation:<\/p>\n<pre>\/\/ Old school: Task chain\r\nIAsyncActionWithProgress&lt;int&gt;^\r\n    EnableWidgetByIdAsync(String^ id, bool enable)\r\n{\r\n    return create_async([=](<span style=\"border: 1px currentcolor; border-style: solid none none solid;\">progress_reporter&lt;int&gt; pr<\/span><span style=\"border: 1px currentcolor; border-style: solid solid solid none;\">ogress,<\/span>\r\n                           <span style=\"border: solid 1px currentcolor; border-top: none;\">cancellation_token cancel<\/span>)\r\n        -&gt; task&lt;void&gt; {\r\n        <span style=\"border: solid 1px currentcolor;\">progress.report(0);<\/span>\r\n        return GetWidgetAsync(id).then(\r\n        [=](Widget^ widget) { \/\/ explicitly: [enable, <span style=\"border: solid 1px currentcolor;\">progress, cancel<\/span>]\r\n            <span style=\"border: solid 1px currentcolor; border-bottom: none;\">ThrowIfCanceled(cancel);<\/span>\r\n            <span style=\"border: solid 1px currentcolor; border-top: none;\">progress.report(1);     <\/span>\r\n            return EnableWidgetAsync(widget, enable);\r\n        });\r\n    });\r\n}\r\n\r\n\/\/ New hotness: co_await\r\nIAsyncAction^ EnableWidgetByIdAsync(String^ id, bool enable)\r\n{\r\n    return create_async([=](<span style=\"border: 1px currentcolor; border-style: solid none none solid;\">progress_reporter&lt;int&gt; pr<\/span><span style=\"border: 1px currentcolor; border-style: solid solid solid none;\">ogress,<\/span>\r\n                           <span style=\"border: solid 1px currentcolor; border-top: none;\">cancellation_token cancel<\/span>)\r\n        -&gt; task&lt;void&gt; {\r\n        <span style=\"border: solid 1px currentcolor;\">progress.report(0);<\/span>\r\n        Widget^ widget = co_await GetWidgetAsync(id);\r\n        <span style=\"border: solid 1px currentcolor; border-bottom: none;\">ThrowIfCanceled(cancel);<\/span>\r\n        <span style=\"border: solid 1px currentcolor; border-top: none;\">progress.report(1);     <\/span>\r\n        co_await EnableWidgetAsync(widget, enable);\r\n    });\r\n}\r\n<\/pre>\n<p>We can generalize into a single pattern:<\/p>\n<pre>IAsyncSomething^\r\n    DoSomethingAsync(Arg1 arg1, Arg2, arg2, ...)\r\n{\r\n    return create_async([=](\r\n        progress_reporter&lt;P&gt; progress<sub>[optional]<\/sub>,\r\n        cancellation_token cancel<sub>[optional]<\/sub>)\r\n        -&gt; task&lt;P&gt; {\r\n        \u27e6 async stuff which may include...\r\n            progress.report(value);<sub>[optional]<\/sub>\r\n            ThrowIfCanceled(cancel);<sub>[optional]<\/sub>\r\n        \u27e7\r\n    });\r\n}\r\n<\/pre>\n<p>You can also register a callback function on the <code>cancellation_<wbr \/>token<\/code> that will be invoked when the activity is canceled. I leave using the cancellation callback as an exercise.<\/p>\n<p>There are also variants for <code>IAsync\u00adOperation<\/code>. I&#8217;ll show just one of them and let you figure out the others:<\/p>\n<pre>\/\/ Old school: Task chain\r\nIAsyncOperationWithProgress&lt;bool, int&gt;^\r\n    EnableWidgetByIdAsync(String^ id, bool enable)\r\n{\r\n    return create_async([=](progress_reporter&lt;int&gt; progress,\r\n                           cancellation_token cancel)\r\n        -&gt; task&lt;<span style=\"border: solid 1px currentcolor;\">bool<\/span>&gt; {\r\n        progress.report(0);\r\n        return GetWidgetAsync(id).then(\r\n        [=](Widget^ widget) { \/\/ explicitly: [enable, progress, cancel]\r\n            ThrowIfCanceled(cancel);\r\n            progress.report(1);\r\n            <span style=\"border: solid 1px currentcolor; border-bottom: none;\">if (!widget) {                                         <\/span>\r\n            <span style=\"border: 1px currentcolor; border-style: none solid;\">    return task_from_result(false); \/\/ widget not found<\/span>\r\n            <span style=\"border: 1px currentcolor; border-style: none solid;\">}                                                      <\/span>\r\n            <span style=\"border: 1px currentcolor; border-style: none solid;\">return EnableWidgetAsync(widget, enable).then(         <\/span>\r\n            <span style=\"border: solid 1px currentcolor; border-top: none;\">    []() { return true; });                            <\/span>\r\n        });\r\n    });\r\n}\r\n\r\n\/\/ New hotness: co_await\r\nIAsyncAction^ EnableWidgetByIdAsync(String^ id, bool enable)\r\n{\r\n    return create_async([=](progress_reporter&lt;int&gt; progress,\r\n                           cancellation_token cancel)\r\n        -&gt; task&lt;<span style=\"border: solid 1px currentcolor;\">bool<\/span>&gt; {\r\n        progress.report(0);\r\n        Widget^ widget = co_await GetWidgetAsync(id);\r\n        ThrowIfCanceled(cancel);\r\n        progress.report(1);\r\n        <span style=\"border: solid 1px currentcolor; border-bottom: none;\">if (!widget) {                             <\/span>\r\n        <span style=\"border: 1px currentcolor; border-style: none solid;\">    co_return false;                       <\/span>\r\n        <span style=\"border: 1px currentcolor; border-style: none solid;\">}                                          <\/span>\r\n        <span style=\"border: 1px currentcolor; border-style: none solid;\">co_await EnableWidgetAsync(widget, enable);<\/span>\r\n        <span style=\"border: solid 1px currentcolor; border-top: none;\">co_return true;                            <\/span>\r\n    });\r\n}\r\n<\/pre>\n","protected":false},"excerpt":{"rendered":"<p>The Parallel Patterns Library has special support for C++\/CX.<\/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-109953","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>The Parallel Patterns Library has special support for C++\/CX.<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/109953","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=109953"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/109953\/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=109953"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=109953"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=109953"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}