How do I show the sharing pane from a Win32 desktop application?

Raymond

A customer wanted to show the sharing pane from their Win32 desktop application. In a UWP application, this would be done by calling Windows.Application­Model.Data­Transfer.Data­Transfer­Manager.Show­Sharing­UI(). Let’s do it in a Win32 desktop app by following the basic rules for projection: Static methods are represented as methods on a “Statics” interface on the activation factory.

Start with the scratch program and make these changes. (Remember, Little Programs do little to no error checking.)

#include <wrl/client.h>
#include <wrl/wrappers/corewrappers.h>
#include <windows.applicationmodel.datatransfer.h>
#include <tchar.h> // Huh? Why are you still using ANSI?
#include <roapi.h>

namespace WRL = Microsoft::WRL;
namespace dt = ABI::Windows::ApplicationModel::DataTransfer;

using Microsoft::WRL::Wrappers::HStringReference;

void OnChar(HWND hwnd, TCHAR ch, int cRepeat)
{
  switch (ch) {
  case TEXT(' '):
    {
      WRL::ComPtr<dt::IDataTransferManagerStatics> dtmStatics;
      RoGetActivationFactory(HStringReference(
        RuntimeClass_Windows_ApplicationModel_DataTransfer_DataTransferManager)
                             .Get(), IID_PPV_ARGS(&dtmStatics));
      dtmStatics->ShowShareUI();
    }
    break;
  }
}

HANDLE_MSG(hwnd, WM_CHAR, OnChar);

Fire up this program, hit the space bar, and… nothing happens.

Okay, so maybe we need to do a tiny bit of error checking after all. The call to Show­Share­UI fails with E_NOT_SET. The reason is that the Show­Share­UI method has an implicit dependency on the current thread’s Core­Window, because it needs to know which window is being shared. But since we are a Win32 desktop program, we don’t have a Core­Window.

Oh no, what do we do?

Enter the interop pattern.

To accommodate Win32 desktop programs, there is a parallel universe of HWND-based methods. In places where WinRT depends on the current thread’s Core­Window, this alternative universe offers a similarly-named method, but with the For­Window suffix, indicating that it operates on classic Win32 HWNDs rather than fancy-pants Core­Windows.

One component of this parallel universe of -For­Window methods consists of interfaces that end in the name Interop. In our case, it’s IData­Transfer­Manager­Interop. This interface is available on the activation factory, the same as the IData­Transfer­Manager­Statics interface. The general pattern is as follows:

XxxStatics XxxInterop
Get­For­Current­View Get­For­Window
Do­Something (implied “for current view”) Do­Something­For­Window

In our case, we have a Show­Sharing­UI() method on the Statics interface, so the corresponding interop method is called Show­Sharing­For­WIndow().

#include <shlobj.h> // IDataTransferManagerInterop

void OnChar(HWND hwnd, TCHAR ch, int cRepeat)
{
  switch (ch) {
  case TEXT(' '):
    {
      WRL::ComPtr<dt::IDataTransferManagerInterop> dtmInterop;
      RoGetActivationFactory(HStringReference(
        RuntimeClass_Windows_ApplicationModel_DataTransfer_DataTransferManager)
                             .Get(), IID_PPV_ARGS(&dtmInterop));
      dtmInterop->ShowShareUIForWindow(hwnd);
    }
    break;
  }
}

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’ll look at that next time.

Bonus chatter: One of my colleagues noted that “data transfer manager” is a poor name for the class, seeing as transferring data is what computers do most of the time anyway.

0 comments

Comments are closed. Login to edit/delete your existing comments