{"id":106251,"date":"2022-02-14T07:07:44","date_gmt":"2022-02-14T15:07:44","guid":{"rendered":"https:\/\/devblogs.microsoft.com\/oldnewthing\/?p=106251"},"modified":"2022-02-15T08:41:54","modified_gmt":"2022-02-15T16:41:54","slug":"20220214-00","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20220214-44\/?p=106251","title":{"rendered":"COM asynchronous interfaces, part 1: The basic pattern"},"content":{"rendered":"<p>You can mark your marshaled COM interfaces as supporting asynchronous calls, which unlocks a brand new calling pattern. When you attach the <a href=\"https:\/\/docs.microsoft.com\/en-us\/windows\/win32\/midl\/async-uuid\"> <code>async_uuid<\/code><\/a> attribute to your interface, COM generates a parallel interface with the same name as the synchronous interface, but with the <code>Async<\/code> prefix. For example, the asynchronous partner of <code>IMumble<\/code> is <code>AsyncIMumble<\/code>. (This is an exception to the general rule that COM interface begin with the letter &#8220;I&#8221;.)<\/p>\n<p>For each method on the synchronous interface, COM creates <i>two<\/i> methods on the asynchronous interface: <code>Begin_<wbr \/>MethodName<\/code> and <code>Finish_<wbr \/>MethodName<\/code>. The parameters to the <code>Begin_<wbr \/>MethodName<\/code> method are all of the <code>[in]<\/code> parameters of the original method, and the parameters to the <code>Finish_<wbr \/>MethodName<\/code> method are all of the <code>[out]<\/code> parameters. A parameter that is annotated as <code>[in, out]<\/code> shows up in <i>both<\/i> methods.<\/p>\n<p>The general pattern for making an asynchronous call is<\/p>\n<ul>\n<li>Query the proxy for <code>ICallFactory<\/code>.<\/li>\n<li>Call <code>ICallFactory::CreateCall<\/code> with the asynchronous interface you want to call. This produces a <i>call object<\/i>.<\/li>\n<li>Call the <code>Begin_<wbr \/>MethodName<\/code> method on the call object.<\/li>\n<li>Go do something else for a while, if you like.<\/li>\n<li>Optionally, check in on the progress of the asynchronous operation by calling <code>ISynchronize::Wait<\/code> on the call object.<\/li>\n<li>Call the <code>Finish_<wbr \/>MethodName<\/code> method to wait for the call to complete and get the results.<\/li>\n<\/ul>\n<p>Today, we&#8217;ll kick the tires a bit. In future articles, we&#8217;ll try out some variations, finishing with a practical application of asynchronous calls that you can use even if your interface isn&#8217;t marked as asynchronous.<\/p>\n<p>Today&#8217;s smart pointer library is (rolls dice)\u00b9 C++\/WinRT.<\/p>\n<pre>#include &lt;windows.h&gt;\r\n#include &lt;stdio.h&gt; \/\/ Horrors! Mixing C and C++!\r\n\r\nstruct SlowPipe :\r\n    winrt::implements&lt;SlowPipe, ::IPipeByte, winrt::non_agile&gt;\r\n{\r\n  \/\/ exit the STA thread when we destruct\r\n  ~SlowPipe() {  PostQuitMessage(0); }\r\n\r\n  STDMETHODIMP Pull(BYTE* buffer, ULONG size, ULONG* written)\r\n  {\r\n    printf(\"Pulling %lu bytes...\\n\", size);\r\n    ULONG index;\r\n    for (index = 0; index &lt; size \/ 2; index++) {\r\n      Sleep(100);\r\n      buffer[index] = 42;\r\n      printf(\"Pulled byte %lu of %lu\\n\", index, size);\r\n    }\r\n    *written = index;\r\n    printf(\"Finished pulling %lu% of %lu bytes\\n\", index, size);\r\n    return S_OK;\r\n  }\r\n\r\n  STDMETHODIMP Push(BYTE* buffer, ULONG size)\r\n  {\r\n    printf(\"Pushing %lu bytes...\\n\", size);\r\n    ULONG index;\r\n    for (index = 0; index &lt; size; index++) {\r\n      Sleep(100);\r\n      printf(\"Pushed byte %08x\\n\", buffer[index]);\r\n    }\r\n    printf(\"Finished pushing %lu bytes\\n\", size);\r\n    return S_OK;\r\n  }\r\n};\r\n<\/pre>\n<p>Our <code>SlowPipe<\/code> object is a pipe that is slow, taking 100ms for each byte. C++\/WinRT objects are agile by default, but we mark ours as <code>winrt::<wbr \/>not_<wbr \/>agile<\/code> to override this, thereby forcing the interface to be marshaled through a proxy. Just for fun, our <code>Pull<\/code> method pulls only half of the bytes requested.<\/p>\n<p>Let&#8217;s create a thread that hosts our <code>SlowPipe<\/code> object.<\/p>\n<pre>struct CreateSlowPipeInfo\r\n{\r\n  winrt::agile_ref&lt;::IPipeByte&gt; agile;\r\n  bool ready = false;\r\n};\r\n\r\n\r\nDWORD CALLBACK ThreadProc(void* p)\r\n{\r\n  winrt::init_apartment(winrt::apartment_type::single_threaded);\r\n\r\n  auto&amp; info = *reinterpret_cast&lt;CreateSlowPipeInfo&gt;(p);\r\n  info.agile = winrt::make&lt;SlowPipe&gt;();\r\n  info.ready = true;\r\n  WakeByAddressSingle(&amp;info.ready);\r\n\r\n  MSG msg;\r\n  while (GetMessage(&amp;msg, nullptr, 0, 0)) {\r\n    TranslateMessage(&amp;msg);\r\n    DispatchMessageW(&amp;msg);\r\n  }\r\n\r\n  winrt::uninit_apartment();\r\n  return 0;\r\n}\r\n<\/pre>\n<p>The thread is given a pointer to a <code>Create\u00adSlow\u00adPipe\u00adInfo<\/code> structure. We initialize COM in single-threaded mode on the thread, create a <code>Slow\u00adPipe<\/code> object, and store an agile reference to that object in the thread creator-provided structure. We then let the thread creator know that the agile reference is ready. And then we process messages until we get a quit message, which will happen when the <code>Slow\u00adPipe<\/code> is destructed.<\/p>\n<p>So let&#8217;s write the code that creates the thread and gets the <code>Slow\u00adPipe<\/code> from that thread.<\/p>\n<pre>winrt::com_ptr&lt;::IPipeByte&gt; CreateSlowPipeOnOtherThread()\r\n{\r\n    CreateSlowPipeInfo info;\r\n    auto nope = info.ready;\r\n\r\n    DWORD id;\r\n    winrt::handle(winrt::check_pointer(\r\n        CreateThread(0, 0, ThreadProc, &amp;info, 0, &amp;id)));\r\n\r\n    while (!info.ready) {\r\n      WaitOnAddress(&amp;info.ready, &amp;nope, sizeof(nope), INFINITE);\r\n    }\r\n    return info.agile.get();\r\n}\r\n<\/pre>\n<p>We create the thread with the <code>Create\u00adSlow\u00adPipe\u00adInfo<\/code> and wait for it to signal that it&#8217;s ready, at which point we convert the agile reference to a <code>com_ptr&lt;IPipe\u00adByte&gt;<\/code> so we can use it locally.<\/p>\n<p>Okay, now on to the main event:<\/p>\n<pre>int main(int, char**)\r\n{\r\n  winrt::init_apartment(winrt::apartment_type::multi_threaded);\r\n\r\n  auto pipe = CreateSlowPipeOnOtherThread();\r\n\r\n  winrt::com_ptr&lt;::AsyncIPipeByte&gt; call;\r\n  auto factory = pipe.as&lt;ICallFactory&gt;();\r\n  winrt::check_hresult(factory-&gt;CreateCall(\r\n    __uuidof(::AsyncIPipeByte), nullptr,\r\n    __uuidof(::AsyncIPipeByte),\r\n    reinterpret_cast&lt;::IUnknown**&gt;(call.put())));\r\n\r\n  printf(\"Beginning the Pull\\n\");\r\n  winrt::check_hresult(call-&gt;Begin_Pull(100));\r\n\r\n  printf(\"Doing something else for a while...\\n\");\r\n  Sleep(100);\r\n\r\n  printf(\"Getting the answer\\n\");\r\n  BYTE buffer[100];\r\n  ULONG actual;\r\n  winrt::check_hresult(call-&gt;Finish_Pull(buffer, &amp;actual));\r\n  printf(\"Pulled %lu bytes\\n\", actual);\r\n\r\n  return 0;\r\n}\r\n<\/pre>\n<p>Once we create the pipe on another thread and marshal it back to the main thread, we make an asynchronous call to the <code>Pull<\/code> method.<\/p>\n<p>First step: Get the factory, which we do by querying the proxy for <code>ICallFactory<\/code>.<\/p>\n<p>Second step: Create a new call. The parameters to <code>Create\u00adCall<\/code> take a little time to get used to.<\/p>\n<ul>\n<li>First is the asynchronous interface you want to call.<\/li>\n<li>Second is the controlling unknown. You usually pass <code>nullptr<\/code> here, but we&#8217;ll see later how you can replace this to get special effects.<\/li>\n<li>Third and fourth are the usual pair of an interface ID and an output pointer. Somewhat cumbersome here is that the final parameter is typed as <code>IUnknown**<\/code> rather than the traditional <code>void**<\/code>, which means you can&#8217;t use the usual <code>IID_PPV_ARGS<\/code> pattern.<\/li>\n<\/ul>\n<p>The call object itself supports the following interfaces:<\/p>\n<ul>\n<li><code>IUnknown<\/code> because all COM objects support <code>IUnknown<\/code>.<\/li>\n<li><code>AsyncIMumble<\/code>, the asynchronous interface you are calling.<\/li>\n<li><code>ISynchronize<\/code>, which we&#8217;ll learn about later.<\/li>\n<li><code>ISynchronize\u00adHandle<\/code>, which we&#8217;ll learn about later.<\/li>\n<li><code>ICancel\u00adMethod\u00adCalls<\/code>, which we&#8217;ll learn about later.<\/li>\n<li><code>IClient\u00adSecurity<\/code>, which you can use to <a href=\"https:\/\/docs.microsoft.com\/en-us\/windows\/win32\/com\/client-security-during-an-asynchronous-call\"> customize the security of the marshaled call<\/a>. I&#8217;m not going to go into this part.<\/li>\n<\/ul>\n<p>You definitely are going to need the <code>AsyncIMumble<\/code>, seeing as that&#8217;s how you&#8217;re going to make the asynchronous call in the first place. The other interfaces might or might not be useful, depending on the scenario.<\/p>\n<p>We call the <code>Begin_<wbr \/>Pull<\/code> method with the input parameters to initiate the pull operation. This call goes out to the helper thread, but since we are calling asynchronously, the call to <code>Begin_<wbr \/>Pull<\/code> returns immediately, while the call gets delivered to the other thread for execution.<\/p>\n<p>We pretend to do some other work for a while, and then come back and call <code>Finish_<wbr \/>Pull<\/code> method to get the answer. This is a blocking call that waits for the operation to complete, and then propagates the unmarshaled output parameters and <code>HRESULT<\/code>.<\/p>\n<p>That&#8217;s the basics of COM asynchronous calls. Next time, we&#8217;ll start getting a little fancier.<\/p>\n<p>\u00b9 The dice are loaded.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Letting things run on their own, and then coming back for the answer later.<\/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-106251","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>Letting things run on their own, and then coming back for the answer later.<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/106251","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=106251"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/106251\/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=106251"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=106251"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=106251"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}