{"id":95745,"date":"2017-03-16T07:00:00","date_gmt":"2017-03-16T21:00:00","guid":{"rendered":"https:\/\/blogs.msdn.microsoft.com\/oldnewthing\/?p=95745"},"modified":"2019-03-13T01:08:07","modified_gmt":"2019-03-13T08:08:07","slug":"20170316-00","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20170316-00\/?p=95745","title":{"rendered":"How do I provide data to the sharing pane from a Win32 desktop application?"},"content":{"rendered":"<p>Last time, we were able to show the sharing pane from a Win32 desktop application, but we didn&#8217;t provide any information to the sharing pane, so all it did was offer to share a screen shot. Today, let&#8217;s provide some data. <\/p>\n<p>This is a continuation of the interop pattern. Repeating the table we had from last time: <\/p>\n<table BORDER=\"1\" STYLE=\"border-collapse: collapse\" CELLPADDING=\"3\">\n<tr>\n<th>XxxStatics<\/th>\n<th>XxxInterop<\/th>\n<\/tr>\n<tr>\n<td>Get&shy;For&shy;Current&shy;View<\/td>\n<td>Get&shy;For&shy;Window<\/td>\n<\/tr>\n<tr>\n<td>Do&shy;Something (implied &#8220;for current view&#8221;)<\/td>\n<td>Do&shy;Something&shy;For&shy;Window<\/td>\n<\/tr>\n<\/table>\n<p>Last time, we used the second case, converting <code>Show&shy;Sharing&shy;UI<\/code> to <code>Show&shy;Sharing&shy;UI&shy;For&shy;Window<\/code>. Today we&#8217;re going to use the first case: Converting <code>Get&shy;For&shy;Current&shy;View<\/code> to <code>Get&shy;For&shy;Window<\/code>. <\/p>\n<p>Start with a blank <a HREF=\"https:\/\/blogs.msdn.microsoft.com\/oldnewthing\/20030723-00\/?p=43073\">scratch program<\/a> and make these changes. (Remember, Little Programs do little to no error checking.) <\/p>\n<pre>\n#include &lt;wrl\/client.h&gt;\n#include &lt;wrl\/event.h&gt;\n#include &lt;wrl\/wrappers\/corewrappers.h&gt;\n#include &lt;windows.applicationmodel.datatransfer.h&gt;\n#include &lt;shlobj.h&gt; \/\/ IDataTransferManagerInterop\n#include &lt;tchar.h&gt; \/\/ Huh? Why are you still using ANSI?\n#include &lt;roapi.h&gt;\n\nnamespace WRL = Microsoft::WRL;\nnamespace awf = ABI::Windows::Foundation;\nnamespace dt = ABI::Windows::ApplicationModel::DataTransfer;\n\nusing Microsoft::WRL::Wrappers::HStringReference;\n\nWRL::ComPtr&lt;IDataTransferManagerInterop&gt; g_dtmInterop;\nWRL::ComPtr&lt;DT::IDataTransferManager&gt; g_dtm;\nEventRegistrationToken g_dataRequestedToken;\n<\/pre>\n<p>Note that in real life, these global variables would be instance variables of some C++ class. <\/p>\n<pre>\nBOOL\nOnCreate(HWND hwnd, LPCREATESTRUCT lpcs)\n{\n  RoGetActivationFactory(HStringReference(\n    RuntimeClass_Windows_ApplicationModel_DataTransfer_DataTransferManager)\n                         .Get(), IID_PPV_ARGS(&amp;g_dtmInterop));\n\n  g_dtmInterop-&gt;GetForWindow(hwnd, IID_PPV_ARGS(&amp;g_dtm));\n\n  auto callback = WRL::Callback&lt;WF::ITypedEventHandler&lt;\n    DT::DataTransferManager*, DT::DataRequestedEventArgs*&gt;&gt;(\n        [](auto&amp;&amp;, DT::IDataRequestedEventArgs* e)\n    {\n      WRL::ComPtr&lt;DT::IDataRequest&gt; request;\n      e-&gt;get_Request(&amp;request);\n\n      WRL::ComPtr&lt;DT::IDataPackage&gt; data;\n      request-&gt;get_Data(&amp;data);\n\n      WRL::ComPtr&lt;DT::IDataPackagePropertySet&gt; properties;\n      data-&gt;get_Properties(&amp;properties);\n\n      \/\/ Title is mandatory\n      properties-&gt;put_Title(HStringReference(L\"Title from Win32\").Get());\n\n      \/\/ Description is optional\n      properties-&gt;put_Description(HStringReference(L\"This text came from a Win32 app\").Get());\n\n      data-&gt;SetText(HStringReference(L\"Text from Win32 app!\").Get());\n\n      return S_OK;\n    });\n\n  g_dtm-&gt;add_DataRequested(callback.Get(), &amp;g_dataRequestedToken);\n\n  return TRUE;\n}\n\nvoid\nOnDestroy(HWND hwnd)\n{\n    g_dtm-&gt;remove_DataRequested(g_dataRequestedToken);\n    g_dtm.Reset();\n    g_dtmInterop.Reset();\n    PostQuitMessage(0);\n}\n\n\nvoid OnChar(HWND hwnd, TCHAR ch, int cRepeat)\n{\n  switch (ch) {\n  case TEXT(' '):\n    g_dtmInterop-&gt;ShowShareUIForWindow(hwnd);\n    }\n    break;\n  }\n}\n\nHANDLE_MSG(hwnd, WM_CHAR, OnChar);\n<\/pre>\n<p>Okay, let&#8217;s see what happened here. <\/p>\n<p>When the window is created, we get the interop interface and save it in the global variable for later use. We then call <code>Get&shy;For&shy;Window<\/code> to obtain the <code>Data&shy;Transfer&shy;Manager<\/code> for our window. In WinRT this would have been a call to <code>Get&shy;For&shy;Current&shy;View<\/code>. <\/p>\n<p>That&#8217;s all for the interop part of this exercise. Everything else is just operating on the WinRT objects at the ABI level instead of at the projection level. <\/p>\n<p>Next we create a callback handler for the <code>Data&shy;Requested<\/code> event. We&#8217;ll look at the body of the handler later. <\/p>\n<p>We then register the handler for the event by calling <code>add_Data&shy;Requested<\/code> and save the registration token so we can unregister later. <\/p>\n<p>Okay, now to look inside the callback: This is a direct translation of <code>Data&shy;Transfer&shy;Manager<\/code> from projection back into ABI. Reading a property becomes a call to the <code>get_PropertyName<\/code> method, and writing a property becomes a call to the <code>put_PropertyName<\/code> method. In our case, we take the <code>Data&shy;Requested&shy;Event&shy;Args<\/code> and get the <code>Request<\/code> property, which is an <code>IData&shy;Request<\/code>. From the <code>IData&shy;Request<\/code> we set the <code>Title<\/code> and <code>Description<\/code> properties, and use the <code>SetText<\/code> method to provide the text that we are sharing. <\/p>\n<p>At destruction, we unregister the event and release the objects. <\/p>\n<p>The final snippet of code is what we saw last time: When the user hits the space bar, open the share pane. But this time, the share pane actually shows something interesting, because our <code>Data&shy;Requested<\/code> event handler provides text to be shared. <\/p>\n<p>Of course, in a real program, you would presumably offer text or other content that is based on the current state or selection rather than just spitting out hard-coded content, but this is just a Little Program. <\/p>\n","protected":false},"excerpt":{"rendered":"<p>Continuing the interop pattern.<\/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-95745","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>Continuing the interop pattern.<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/95745","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=95745"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/95745\/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=95745"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=95745"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=95745"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}