{"id":95735,"date":"2017-03-15T07:00:00","date_gmt":"2017-03-15T21:00:00","guid":{"rendered":"https:\/\/blogs.msdn.microsoft.com\/oldnewthing\/?p=95735"},"modified":"2019-03-13T01:08:04","modified_gmt":"2019-03-13T08:08:04","slug":"20170315-00","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20170315-00\/?p=95735","title":{"rendered":"How do I show the sharing pane from a Win32 desktop application?"},"content":{"rendered":"<p>A customer wanted to show the sharing pane from their Win32 desktop application. In a UWP application, this would be done by calling <code>Windows.Application&shy;Model.Data&shy;Transfer.Data&shy;Transfer&shy;Manager.Show&shy;Sharing&shy;UI()<\/code>. Let&#8217;s do it in a Win32 desktop app by following <a HREF=\"https:\/\/blogs.msdn.microsoft.com\/oldnewthing\/20160629-00\/?p=93775\">the basic rules for projection<\/a>: Static methods are represented as methods on a &#8220;Statics&#8221; interface on the activation factory. <\/p>\n<p>Start with <a HREF=\"https:\/\/blogs.msdn.microsoft.com\/oldnewthing\/20030723-00\/?p=43073\">the scratch program<\/a> and make these changes. (Remember, Little Programs do little to no error checking.) <\/p>\n<pre>\n<font COLOR=\"blue\">#include &lt;wrl\/client.h&gt;\n#include &lt;wrl\/wrappers\/corewrappers.h&gt;\n#include &lt;windows.applicationmodel.datatransfer.h&gt;\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 dt = ABI::Windows::ApplicationModel::DataTransfer;\n\nusing Microsoft::WRL::Wrappers::HStringReference;\n\nvoid OnChar(HWND hwnd, TCHAR ch, int cRepeat)\n{\n  switch (ch) {\n  case TEXT(' '):\n    {\n      WRL::ComPtr&lt;dt::IDataTransferManagerStatics&gt; dtmStatics;\n      RoGetActivationFactory(HStringReference(\n        RuntimeClass_Windows_ApplicationModel_DataTransfer_DataTransferManager)\n                             .Get(), IID_PPV_ARGS(&amp;dtmStatics));\n      dtmStatics-&gt;ShowShareUI();\n    }\n    break;\n  }\n}\n\nHANDLE_MSG(hwnd, WM_CHAR, OnChar);\n<\/font><\/pre>\n<p>\nFire up this program, hit the space bar,\nand&hellip; nothing happens.\n<\/p>\n<p>\nOkay, so maybe we need to do a tiny bit of error checking\nafter all.\nThe call to\n<code>Show&shy;Share&shy;UI<\/code> fails with\n<code>E_NOT_SET<\/code>.\nThe reason is that the\n<code>Show&shy;Share&shy;UI<\/code> method\nhas an implicit dependency on the current thread&#8217;s\n<code>Core&shy;Window<\/code>,\nbecause it needs to know\nwhich window is being shared.\nBut since we are a Win32 desktop program,\nwe don&#8217;t have a\n<code>Core&shy;Window<\/code>.\n<\/p>\n<p>\nOh no, what do we do?\n<\/p>\n<p>\nEnter the interop pattern.\n<\/p>\n<p>\nTo accommodate Win32 desktop programs,\nthere is a parallel universe of <code>HWND<\/code>-based\nmethods.\nIn places where WinRT depends on the current thread&#8217;s\n<code>Core&shy;Window<\/code>,\nthis alternative universe offers a similarly-named method,\nbut with the <code>For&shy;Window<\/code> suffix,\nindicating that it operates on classic Win32 <code>HWND<\/code>s\nrather than fancy-pants\n<code>Core&shy;Window<\/code>s.\n<\/p>\n<p>\nOne component of\nthis parallel universe of\n<code>-For&shy;Window<\/code> methods\nconsists of interfaces that end in the name <code>Interop<\/code>.\nIn our case, it&#8217;s\n<code>IData&shy;Transfer&shy;Manager&shy;Interop<\/code>.\nThis interface is available on the activation factory,\nthe same as the\n<code>IData&shy;Transfer&shy;Manager&shy;Statics<\/code> interface.\nThe general pattern is as follows:\n<\/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>\nIn our case, we have a\n<code>Show&shy;Sharing&shy;UI()<\/code> method\non the <code>Statics<\/code>\ninterface,\nso the corresponding interop method is called\n<code>Show&shy;Sharing&shy;For&shy;WIndow()<\/code>.\n<\/p>\n<pre>\n#include &lt;shlobj.h&gt; \/\/ IDataTransferManagerInterop\n\nvoid OnChar(HWND hwnd, TCHAR ch, int cRepeat)\n{\n  switch (ch) {\n  case TEXT(' '):\n    {\n      <font COLOR=\"blue\">WRL::ComPtr&lt;dt::IDataTransferManagerInterop&gt; dtmInterop;<\/font>\n      RoGetActivationFactory(HStringReference(\n        RuntimeClass_Windows_ApplicationModel_DataTransfer_DataTransferManager)\n                             .Get(), IID_PPV_ARGS(<font COLOR=\"blue\">&amp;dtmInterop<\/font>));\n      <font COLOR=\"blue\">dtmInterop-&gt;ShowShareUIForWindow(hwnd);<\/font>\n    }\n    break;\n  }\n}\n<\/pre>\n<p>Okay, so now we show the share pane, but the pane just offers to share a screen shot. How can we get the pane to offer custom data provided by the program? We&#8217;ll look at that next time. <\/p>\n<p><b>Bonus chatter<\/b>: One of my colleagues noted that &#8220;data transfer manager&#8221; is a poor name for the class, seeing as transferring data is what computers do most of the time anyway. <\/p>\n","protected":false},"excerpt":{"rendered":"<p>Unwrapping the projection, but now with interop.<\/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-95735","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>Unwrapping the projection, but now with interop.<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/95735","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=95735"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/95735\/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=95735"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=95735"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=95735"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}