UWP with Desktop Extension – Part 3

desktop_yellow

If you haven’t read part 1 or part 2 of this series yet, please start there first. I have covered the “Hello World” version of a UWP with Desktop extension and explained how to launch different process types and pass in arguments. Now the next set of questions I want to answer in this post are:

  • How to establish a communication channel between the components?
  • How to send requests and receive responses from either side?
  • How to handle process exit scenarios?

TL; DR;

Short answers: An AppServiceConnection can be used to connect between the components and to allow bi-directional communication via ValueSets. Typically you want to host the AppService in-proc with your UWP app in this type of scenario.

Just show me the code on github …
https://github.com/StefanWickDev/UWP-FullTrust/tree/master/UWP_FullTrust_3

Let me run your sample from the Microsoft Store …
https://www.microsoft.com/store/apps/9NR0G35Q2F65

Declaring the AppService

The first step is to declare the AppService extension in our manifest, which is what will provide us with a two-way communication pipe between our components:

<Extensions>
 <uap:Extension Category="windows.appService">
  <uap:AppService Name="SampleInteropService" />
 </uap:Extension>
 <desktop:Extension Category="windows.fullTrustProcess" Executable="FullTrust\FullTrust.exe" />
</Extensions>

For full details on AppServices in the Universal Windows Platform our developer documentation has this good read: https://docs.microsoft.com/en-us/windows/uwp/launch-resume/how-to-create-and-consume-an-app-service

Establishing the Connection

Now in order to establish the connection, let’s take a look at our WPF app. One of the first things it does during launch is to establish the connection to the AppService, and then retain the instance of the AppServiceConnection for the lifetime of the connection. We are also hooking up the event handlers here to receive requests and to get notified when the connection gets closed:

// MainWindow.xaml.cs in WPF project
private async void InitializeAppServiceConnection()
{
 connection = new AppServiceConnection();
 connection.AppServiceName = "SampleInteropService";
 connection.PackageFamilyName = Package.Current.Id.FamilyName;
 connection.RequestReceived += Connection_RequestReceived;
 connection.ServiceClosed += Connection_ServiceClosed;

 AppServiceConnectionStatus status = await connection.OpenAsync();
 if (status != AppServiceConnectionStatus.Success)
 {
  // something went wrong ...
  MessageBox.Show(status.ToString());
  this.IsEnabled = false;
 } 
}

On the other side in the UWP, this will now trigger the OnBackgroundActivated event, and we’ll grab a reference to the AppServiceConnection instance there as well and hold on to it.

In our case the UWP is already running in the foreground, but note that it doesn’t have to: Client processes can also connect to the AppService if the foreground app is not running. It would activate the UWP in the background and establish the AppServiceConnection. The UWP process would then continue running in the background for as long as the connection is active.

// App.xaml.cs in UWP project
protected override void OnBackgroundActivated(BackgroundActivatedEventArgs args)
{
 base.OnBackgroundActivated(args);

 if (args.TaskInstance.TriggerDetails is AppServiceTriggerDetails details)
 {
  // only accept connections from callers in the same package
  if (details.CallerPackageFamilyName == Package.Current.Id.FamilyName)
  {
   // connection established from the fulltrust process
   AppServiceDeferral = args.TaskInstance.GetDeferral();
   args.TaskInstance.Canceled += OnTaskCanceled;

   Connection = details.AppServiceConnection;
   AppServiceConnected?.Invoke(this, args.TaskInstance.TriggerDetails as AppServiceTriggerDetails);
  }
 }
}

Sending Requests and Responses

Now that the connection has been established and either side keeps a reference to the AppServiceConnection instances, we can send requests from either side, and respond to them accordingly.

Scenario 1 – UWP sends request to desktop extension

UWP apps don’t have access to the registry. Let’s assume for an LOB enterprise scenario I need to read a certain reg key. The UWP can use a desktop extension to get the job done, by sending an AppServiceRequest that contains the requested key. The desktop extension can then query the registry and send the name/value pairs back to the UWP as an AppServiceResponse.

screenshot8

// MainPage.Xaml.cs in UWP project
private async void btnClick_ReadKey(object sender, RoutedEventArgs e)
{
 ValueSet request = new ValueSet();
 request.Add("KEY", tbKey.Text);
 AppServiceResponse response = await App.Connection.SendMessageAsync(request);

// display the response key/value pairs
 tbResult.Text = "";
 foreach (string key in response.Message.Keys)
 {
 tbResult.Text += key + " = " + response.Message[key] + "\r\n";
 }
}

This triggers the registry reading code in the WPF app. The implementation can be found here on github in the ‘Connection_RequestReceived’ event handler. In a real production scenario you wouldn’t implement this extension as a windowed WPF app of course, but instead use a headless background process. But since we need UI for scenario #2, I went with WPF …

Scenario 2 – Desktop extension sends request to UWP

To show the reverse communication flow I am just picking a dummy scenario: I will send two double values from WPF to UWP and let the UWP app respond with the sum of both:

screenshot9

// MainWindow.xaml.cs in WPF project
private async void Button_Click(object sender, RoutedEventArgs e)
{
 // ask the UWP to calculate d1 + d2
 ValueSet request = new ValueSet();
 request.Add("D1", d1);
 request.Add("D2", d2);
 AppServiceResponse response = await connection.SendMessageAsync(request);
 double result = (double)response.Message["RESULT"];
 tbResult.Text = result.ToString();
}
// in MainPage.Xaml.cs in UWP project
private async void AppServiceConnection_RequestReceived(AppServiceConnection sender, AppServiceRequestReceivedEventArgs args)
{
 double d1 = (double)args.Request.Message["D1"];
 double d2 = (double)args.Request.Message["D2"];
 double result = d1 + d2;
 
 ValueSet response = new ValueSet();
 response.Add("RESULT", result);
 await args.Request.SendResponseAsync(response);

// log the request in the UI for demo purposes
 await this.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
 {
 tbRequests.Text += string.Format("Request: {0} + {1} --> Response = {2}\r\n", d1, d2, result);
 });
}

 

Handling Process Exit Scenarios

Now what happens if one side of the communication pipeline goes away, for whatever reason? It’s up to the app to handle this and decide what should happen. Generally speaking there are three options: try to relaunch the companion component, or keep going without the companion (if it’s non-essential), or failfast to terminate yourself. For our demo I will implement two scenarios:

Scenario 1 – UWP will relaunch closed WPF

// MainPage.xaml.cs in UWP project
private async void MainPage_AppServiceDisconnected(object sender, EventArgs e)
{
 await Dispatcher.RunAsync(CoreDispatcherPriority.Normal, ()=>
 {
  // disable UI to access the connection
  btnRegKey.IsEnabled = false;

  // ask user if they want to reconnect
  Reconnect();
 }); 
}

private async void Reconnect()
{
 if (App.IsForeground)
 {
  MessageDialog dlg = new MessageDialog("Connection to desktop process lost. Reconnect?");
  UICommand yesCommand = new UICommand("Yes", async (r) =>
  {
   await FullTrustProcessLauncher.LaunchFullTrustProcessForCurrentAppAsync();
  });
  dlg.Commands.Add(yesCommand);
  UICommand noCommand = new UICommand("No", (r) => { });
  dlg.Commands.Add(noCommand);
  await dlg.ShowAsync();
 }
}

Scenario 2 – WPF will terminate itself when UWP closes

// MainWindow.xaml.cs in WPF project
private void Connection_ServiceClosed(AppServiceConnection sender, AppServiceClosedEventArgs args)
{
 // connection to the UWP lost, so we shut down the desktop process
 Dispatcher.BeginInvoke(DispatcherPriority.Normal, new Action(() =>
 {
  Application.Current.Shutdown();
 })); 
}

This is it for part 3 of this series. Hopefully I answered most of the question around communication between the app and its extension in this sample. If not, please leave comments here, hit me up on Twitter or post your questions on Stackoverflow. If they are tagged with ‘UWP’ they will show on my radar.

Next up: Part 4 – Submitting to the Microsoft Store

UWP with Desktop Extension – Part 2

desktop_blue

If you haven’t read part 1 of this series yet, please start there first. I have covered the basic project setup in VS and walked through the “Hello World” version of a UWP with Desktop extension. Now the next set of questions I want to answer in this post are:

  • What type of processes can I use as extensions?
  • What about EXEs that are not in my package?
  • Can I have multiple Desktop extensions for my app?
  • How do I pass parameters into those EXEs?

TL;DR;

Short answers: Any type of Win32 or .NET desktop project type can be used. Can be background-only or with UI. Can come from the package or from elsewhere (read the fine print below), and you can launch with custom command line parameters.

Just show me the code on github …
https://github.com/StefanWickDev/UWP-FullTrust/tree/master/UWP_FullTrust_2

Let me run your sample from the Microsoft Store …
https://www.microsoft.com/store/apps/9PLMLGKSCZQW

Multiple Desktop Processes

If you have studied the ‘windows.fullTrustProcess’ extension schema and corresponding API surface you have noticed that there is only one extension per <Application> node in your package. For multi-process scenarios, you implement them in the declared extension process. There you can use the Process class (.NET) or CreateProcess API (Win32) to create and manage your child processes. To see how this is done, take a look at the “Launcher” project in my sample #2 , which launches several different process types based on input from the UWP.

// determine the package root, based on own location
string result = Assembly.GetExecutingAssembly().Location;
int index = result.LastIndexOf("\\");
string rootPath = $"{result.Substring(0, index)}\\..\\";

// process object to keep track of your child process
Process newProcess = Process.Start(rootPath + @"Win32\Win32.exe");

screenshot3

In-package vs out-of-package

Launching EXEs that come with your package is easy, as the sample demonstrates. You know where they are located and how to launch them as they are your binaries. You can also launch EXEs from other locations on the system. The sample shows this by launching mstsc.exe (the system’s remote desktop app). Be careful here though: In Windows 10 S mode, only Microsoft-signed code can run (OS binaries & apps from the Microsoft Store), so you can’t just CreateProcess/Process.Start an EXE that you’ve downloaded from a share or website. That will fail in S mode. Launching mstsc or notepad will work of course as they are Microsoft-signed.

Another detail to be aware of is process identity: EXEs from your package will be launched with your package’s identity. EXEs from other locations will run under their own identity. Running with package identity also means those desktop processes have the same state separation for Registry and AppData as Desktop Bridge apps (learn all the details here).

You can easily visualize the identity grouping in the task bar and task manager, as the processes are grouped together – whereas the Remote Desktop app is separate from the UWP app:

screenshot6

Background Processes

As you can see in the sample, the desktop extension can run as a headless background process. This can be very powerful as you are in control of the lifetime of this process. It can run for the entire duration of the user session. However, with great power comes great responsibility and you should make sure you don’t burn CPU without delivering user value, especially when run on battery. In my sample I am using a 60 sec timeout on my background process (even though it is not adding any value), just to give folks enough time to find it in task manager to verify its existence.

Also note that running a fulltrust background process for long periods of time may delay your app from getting updated.

Passing in Launch Parameters

From the extension schema, the API surface and/or the MSDN snippet you may have already gathered that the FullTrustProcessLauncher only accepts a finite list of predefined command line arguments that get passed to the desktop extension process. This design is based on the principle, that a less trusted process should not be able to send arbitrary input to a more trusted process. They should communicate via well-defined protocols. Here is how I am using predefined parameter groups in my sample to launch the various types of processes:

<desktop:Extension Category="windows.fullTrustProcess" Executable="Launcher\Launcher.exe">
 <desktop:FullTrustProcess>
 <desktop:ParameterGroup GroupId="Background" Parameters="/background" />
 <desktop:ParameterGroup GroupId="WPF" Parameters="/wpf" />
 <desktop:ParameterGroup GroupId="WinForms" Parameters="/winforms" />
 <desktop:ParameterGroup GroupId="Win32" Parameters="/win32" />
 <desktop:ParameterGroup GroupId="RemoteDesktop" Parameters="/mstsc" />
 <desktop:ParameterGroup GroupId="Parameters" Parameters="/parameters" />
 </desktop:FullTrustProcess>
</desktop:Extension>

In the UWP app code, I now use the FullTrustProcessLauncher overload that takes the ParameterGroupID as string:

if (ApiInformation.IsApiContractPresent("Windows.ApplicationModel.FullTrustAppContract", 1, 0))
{
 await FullTrustProcessLauncher.LaunchFullTrustProcessForCurrentAppAsync("Background");
}

If you own the code on both sides you can use the local AppData to share complex data from the calling app to the desktop process. Furthermore, from your desktop extension process you can launch other desktop process with arbitrary command line arguments, as those processes have the same integrity, as shown in the sample as scenario 2.

UWP side (MainPage.cs):

if (ApiInformation.IsApiContractPresent("Windows.ApplicationModel.FullTrustAppContract", 1, 0))
{
 // store command line parameters in local settings
 // so the Lancher can retrieve them and pass them on
 ApplicationData.Current.LocalSettings.Values["parameters"] = tbParameters.Text;

 await FullTrustProcessLauncher.LaunchFullTrustProcessForCurrentAppAsync("Parameters");
}

Win32 side (Program.cs)

string parameters = ApplicationData.Current.LocalSettings.Values["parameters"] as string;
Process newProcess = Process.Start(rootPath + @"WPF\WPF.exe", parameters);

screenshot7

This is it for part 2 of this series. Hopefully I answered most of the question around process launching and parameters in this sample. If not, please leave comments here, hit me up on Twitter or post your questions on Stackoverflow. If they are tagged with ‘UWP’ they will show on my radar.

Next up: Part 3 – Bi-directional communication between components

UWP with Desktop Extension – Part 1

desktop_purple

Adding a desktop extension component to your UWP app package is a great way to make your universal app even better on PC by lighting up PC-specific capabilities. Recently on Stackoverflow I have seen a number of questions coming up around this topic, so I decided to write up a quick tutorial to help de-mystify various aspects around this useful feature:

Part 1 – Getting started, hello world (this post)
Part 2 – Launching multiple processes, passing in parameters
Part 3 – Communicating between components
Part 4 – Submitting the package to the Microsoft Store

TL;RD;

Including a desktop extension (‘windows.fullTrustProcess’) in your UWP app package lets your UWP app light up PC-specific capabilities when run on the Windows 10 desktop SKU (including Windows 10 S mode). The extension code runs at the full privileges of the user and has access to all public APIs on the machine. Your app will still be able to run on all SKUs of Windows 10 (e.g. Hololens) – it just won’t light up the desktop extension on those devices. This feature has been introduced with the Windows 10 Anniversary Update 1607 (build 14393, aka Redstone 1).

Show me the code for “Hello World” on github
https://github.com/StefanWickDev/UWP-FullTrust/tree/master/UWP_FullTrust_1

Let me try your “Hello World” app from the Microsoft Store
https://www.microsoft.com/store/apps/9ND9W9HWSWNS

Project Setup

With Visual Studio 2017 Update 5 (and later), creating a UWP solution with desktop extension is fairly straight forward now. Here is a step-by-step guide to create your first UWP app that lights up powerful desktop code:

Add extension and packaging projects

In your UWP VS solution, add a “Windows Classic Desktop” project to implement your extension. This could be any type of Win32 or .NET project in any language. For “Hello World” I am adding a C# Console project. Next you need to add a “Windows Application Packaging Project” (look for it in the “Windows Universal” category).

So your solution setup looks like in the screenshot below. In order to package both the UWP and the desktop code in one app package, add both as Application references to the Packaging project:

AddAppRefs

Making the code work together

Now to connect the two projects we need to declare the extension in the package manifest. For this open the Package.appxmanifest file in the Packaging project (“Package”) in XML editing mode and add the following section within the <Application> node:

<Extensions>
 <desktop:Extension
   xmlns:desktop="http://schemas.microsoft.com/appx/manifest/desktop/windows10"
   Category="windows.fullTrustProcess"
   Executable="DesktopExtension\DesktopExtension.exe" />
</Extensions>

Note that the Packaging project by default adds the ‘runFullTrust’ capability to your manifest, which needs to be declared for this extension. Note that this is a restricted capability and will require an additional on-boarding review for the public Microsoft Store – more details on this in part 4 of this series.

To invoke the extension, we are using the FullTrustProcessLauncher API from the UWP Desktop Extension SDK (which is part of the Windows SDK and should already be on your machine). So let’s add a reference to this SDK from our UWP project (“Hello World”):

AddSDKref

Now in your UWP app code, add a line of code to invoke the desktop extension component. It is very important to wrap this into an if-statement as shown, to make sure the app is still universal and can run on all current and future SKUs of Windows 10. We want to launch the extension only on devices that support this contract, in this case on Desktop devices.

if (ApiInformation.IsApiContractPresent("Windows.ApplicationModel.FullTrustAppContract", 1, 0))
{
  await FullTrustProcessLauncher.LaunchFullTrustProcessForCurrentAppAsync();
}

In our desktop extension code (in Program.cs), we just add a quick piece of code for testing/demo purposes:

class Program
{
 static void Main(string[] args)
 {
  Console.Title = "Hello World";
  Console.WriteLine("This process has access to the entire public desktop API surface");
  Console.WriteLine("Press any key to exit ...");
  Console.ReadLine();
 }
}

Run, test and debug

First, double check the configuration properties for solution and make sure it looks like this picture for all configurations you care about (architecture & debug/release). Specifically, you want to uncheck the “Deploy” action for the UWP, since deploy will done from the Packaging Project.

screenshot10

Now make sure you have set the “Package” project as the solution’s start up project in VS, and “Hello World” is its application entry point. Now hit F5 and test out your project. Debugging the UWP code continues to work as before. In order to debug the desktop code, launch without debugging and manually attach to the desktop process in VS. The latter should become more seamless in an upcoming update to VS (I believe the work is scheduled for Update 8), which will let you debug across the UWP/Desktop boundary seamlessly.

screenshot5

This is it for my first post in this tutorial series. Now that you have seen “Hello World” I hope you can imagine some of the possibilities this enables. Keep in mind the desktop extension can be any type of project, e.g. a C++ background process, a VB Winforms app, a C# WPF app, etc. – or any combination of those and it has access to the full public API surface on the machine. More on this in the next post.

Also see my earlier blog posts that use the same pattern to implement some concrete desktop scenarios – UWP with Systray Extension & Office Interop with UWP.

Next up: Part 2 – Launching multiple processes, passing in parameters

 

UWP @ Ignite – Demo code and session links

Had a great time last week at Microsoft Ignite 2017, meeting many customers, partners and friends. I was glad to have the opportunity to present a session about UWP app development with Ginny Caughey as my co-presenter. Thank you Ginny for all the great work!

As a follow-up here are the relevant links:

I have also put my Org Tracker Demo into the Windows Store, if you don’t want to build it from source code. You need to be on Windows 10 build 16278 or later (Fall Creators Update) in order to install and run it. Click the badge to install:

Get it on Windows 10

Here is a list of other great Ignite sessions related to UWP & client app development:

 

App of the week – Paint.NET

Super excited about the release of Paint.NET in the Windows Store. One of my favorite Windows apps, finally in the Store and available on my Surface Laptop running Windows 10 S.

This app is using the Desktop Bridge platform and tooling work that was delivered in the Windows 10 Anniversary Update. This packaging and deployment option for Windows desktop applications provides a number of great benefits, including being able to reach customers on Windows 10 S, distribute and monetize via the Windows Store and many more – here is a blog post from the Paint.NET developer, so don’t just take my word for it:

https://blog.getpaint.net/2017/09/29/paint-net-is-now-available-on-the-windows-store/

Also great to see the use of a newer feature from the Windows 10 Creators Update: Thumbnail handlers for Desktop Bridge apps. This feature allows apps to declare a thumbnail provider for their supported file types, so that explorer can display. Here is how it looks for a file I produced with Paint.NET and saved as .pdn file:

thumbnailHandler

Here is how you declare your thumbnail handlers in your app’s appxmanifest file:
https://docs.microsoft.com/en-us/windows/uwp/porting/desktop-to-uwp-extensions#show

<Extension Category="windows.fileTypeAssociation">
 <FileTypeAssociation Name="[AppID]">
  <SupportedFileTypes>
   <FileType>"[FileExtension]"</FileType>
  </SupportedFileTypes>
  <ThumbnailHandler
    Clsid ="[Clsid ]"
    Cutoff="[Cutoff]"
    Treatment="[Treatment]" />
 </FileTypeAssociation>
</Extension>

This is one of the extension features in the Windows app model that allows apps to integrate with the system (in this case Explorer) in an out-of-proc way, so even in case the app code crashes, it can’t bring down the Explorer process (like some extensibility mechanisms of the past did) – making Windows better for everyone.

If you don’t have the app already, you can get it from the Windows Store here.

UWP app with Systray extension

A common piece of feedback from folks exploring the move from Win32/NET to UWP is about the lack of Systray (aka notification area) support in UWP. It is true that UWP code can’t run in the Systray, however a UWP package can contain a Win32/NET component that can put itself into the Systray. The UWP package will still be universal (run on Surface Hub, Windows Phone, etc.), and light up the PC-specific Systray functionality on the desktop edition only. In this post I will explain how this can be accomplished on Windows 10.

Capture

TL;DR
See source code on GitHub and install the demo app from the Windows Store:
Get it on Windows 10

Details
First step is adding a WinForms project to your UWP solution. It can be done in C++/Win32 as well, but personally I find WinForms to be the most convenient framework for legacy Systray component development. Next add a class file (in my case called ‘SystrayApplicationContext.cs’) to implement all your systray functionality.

SolutionExplorer

To connect the UWP app and the WinForms systray component, we will be using the following two UWP platform features on Windows 10: FullTrustProcessLauncher and AppService. For the former we need to add a reference to the Windows 10 Desktop Extensions SDK:

AddReference

Now we can declare the “windows.fullTrustProcess” and “windows.AppService” extensions in the manifest for our UWP app package. Note also the two capability declarations. The first one is needed for launching the WinForms code from the UWP, the second one we will need in order to intercept the CloseRequested event (when the user hits the “X” on the window). The latter is somewhat unrelated to the topic of this post, but it’s an implementation choice I made for the sample app – and might be useful for your similar scenarios. Note that this API is available in the Creators Update in preview state.

manifest

With the project structure and manifest declarations in place, we can start implementing the desired functionality. First, we want to intercept the user’s close gesture by subscribing to the CloseRequested event:

SystemNavigationManagerPreview mgr =
 SystemNavigationManagerPreview.GetForCurrentView();
mgr.CloseRequested += SystemNavigationManager_CloseRequested;

When the event got triggered we let the user decide if/how they want to close the app. If they chose “Close to Systray” we will launch our WinForms component that will continue to run our code in the notification area. Note that I am only making this call on systems that support the FullTrustAppContract. This way my app will still be universal and work correctly on all editions of Windows 10, such as Surface Hub or Windows Phone:

case CloseAction.Systray:
 if (ApiInformation.IsApiContractPresent(
  "Windows.ApplicationModel.FullTrustAppContract", 1, 0))
 {
 await FullTrustProcessLauncher.LaunchFullTrustProcessForCurrentAppAsync();
 }

Now switching over to the WinForms component. All the relevant code lives in SystrayApplicationContext.cs. I am implementing basic functionality here in the context menu to demonstrate a couple of common concepts:

  1. Open UWP” – restores the UWP app back to the foreground
  2. Send message to UWP” – sends a message via AppService, the UWP will display it as toast (if in background) or dialog (if in foreground)
  3. Open legacy companion” – displays a WinForms UI that is implemented in the same component, included in our UWP package
  4. Exit” – exits both the WinForms and UWP processes

Here is how we hook up the menu handlers. Explore the full source code on GitHub for details on each of the menu actions.

public SystrayApplicationContext()
{
 MenuItem openMenuItem =
 new MenuItem("Open UWP", new EventHandler(OpenApp));
 MenuItem sendMenuItem =
 new MenuItem("Send message to UWP", new EventHandler(SendToUWP));
 MenuItem legacyMenuItem =
 new MenuItem("Open legacy companion", new EventHandler(OpenLegacy));
 MenuItem exitMenuItem = new MenuItem("Exit", new EventHandler(Exit));
 openMenuItem.DefaultItem = true;

 notifyIcon = new NotifyIcon();
 notifyIcon.DoubleClick += new EventHandler(OpenApp);
 notifyIcon.Icon = SystrayComponent.Properties.Resources.Icon1;
 notifyIcon.ContextMenu = new ContextMenu(new MenuItem[]
   { openMenuItem, sendMenuItem, legacyMenuItem, exitMenuItem });
 notifyIcon.Visible = true;
}

Two of the actions I want to highlight real quick, as they are using UWP features, called from the WinForms component, which may be a bit of a new concept for some readers. To get access to those APIs (AppListEntry and AppServiceConnection) I just need to add a reference to the Windows.winmd in my WinForms project. Then I can make these calls:

private async void OpenApp(object sender, EventArgs e)
{
 IEnumerable<AppListEntry> appListEntries = await Package.Current.GetAppListEntriesAsync();
 await appListEntries.First().LaunchAsync();
}

private async Task SendToUWP(ValueSet message)
{ 
 if (connection == null)
 {
  connection = new AppServiceConnection();
  connection.PackageFamilyName = Package.Current.Id.FamilyName;
  connection.AppServiceName = "SystrayExtensionService";
  connection.ServiceClosed += Connection_ServiceClosed;
  AppServiceConnectionStatus connectionStatus = await connection.OpenAsync();
 }
 await connection.SendMessageAsync(message);
}

Hope this information was useful for some of you and will help you when you make the jump from Win32/NET to UWP on Windows 10. Please leave your questions and comments here and I will respond as soon as I can.

UpdateTask for Desktop Bridge apps

We had a number of folks asking this question during //BUILD2017 at the Desktop Bridge booth, and today it came up again on Stackoverflow, so I decided to publish a sample and explain it here: How can I trigger some code when an update for my Win32/NET app has been deployed from the Windows Store?

tile
Source code on GitHub

Before I answer it, let me say that I think most apps won’t ever need to do this as they can run whatever new code they need to run when the app is launched the next time. However, for those cases where you do need to run code in the background automatically after the update has been deployed there is the UWP UpdateTask. If you have a packaged Win32/NET app that you brought to the Windows Store via Desktop Bridge, you can now utilize this task for your app in pretty much the same way as a regular UWP app would implement it. I have posted a WinForms app sample on GitHub – let me walk you through the details. First thing we need to do is extend our UWP app package with an extensions for the background task:

<Extensions>
  <Extension Category="windows.updateTask"
             EntryPoint="BackgroundTasks.UpdateTask" />
</Extensions>

To implement the background task we need to create a Windows Runtime component. So let’s add a project of that type to our solution in Visual Studio and name it “BackgroundTasks”:

addproject

All we need to do in this project is implement our UpdateTask class, derived from IBackgroundTask. For the sample we will just display the new package version in a toast notification:

namespace BackgroundTasks
{
    public sealed class UpdateTask : IBackgroundTask
    {
        public void Run(IBackgroundTaskInstance taskInstance)
        {
            PackageVersion version = Package.Current.Id.Version;
            string message = string.Format(
                "WinForms app updated to {0}.{1}.{2}.{3}",
                version.Major,
                version.Minor,
                version.Build,
                version.Revision);
            ToastHelper.ShowToast(message);
        }
    }
}

 

That’s all it takes to set this up. In case you need to execute some of your Win32/NET code outside of the UWP process that is hosting your task, you can do so using the FullTrustProcessLauncher API (not shown in this sample, but we have other samples for that API).

To see the sample in action, take the following steps:

  1. build and deploy the solution on your PC
  2. change the version number in the package manifest
  3. deploy the app again

Result: UpdateTask gets triggered and runs your code which displays the new version number

toast

Note: if you are not using Visual Studio/msbuild to build & package your own application, you will also need to add the “windows.activatableClass.inProcessServer” extension in your package manifest. VS/msbuild does this automatically for you, for any Windows Runtime components referenced by your app project – but if you need to do this manually check the appmanifest.xml file in the build output of the sample as reference.

UWP calling Office Interop APIs

Following up on what we talked about at BUILD, here is another scenario that is common for LOB Enterprise desktop app developers: Using Microsoft.Office.Interop.* APIs to automate tasks in Office apps installed on the desktop. I have put together a small sample that shows how this can be done from a UWP app on Windows 10 Anniversary Update and above. Hope this will be useful for folks who have existing code and skills in this space and want to move on to UWP.

What does the sample do? The task is to automate Excel with the interop APIs in order to populate a spreadsheet with the content of a Telerik data grid control in my UWP. This is a fairly simple example, but you get the idea how you can now utilize those APIs for Office automation from your UWP app package.

How does it work? The UWP is using the FullTrustProcessLauncher API from the Desktop extension SDK to activate a .NET component from its package that is making the calls to the Microsoft.Office.Interop.* APIs. We are using an AppService to communicate between the two parts of the app package.

Even though we are using a desktop-only API here, the UWP app can still be universal and run on all Windows 10 devices like Windows Phone, Surface Hub, Xbox, etc. – and light up the Office automation functionality on PC only.

screenshot

TL;DR
See source code on GitHub and/or get the demo app from the Store:
Get it on Windows 10

Details
First thing we need to do is extend our UWP app package with two extensions: (a) ‘windows.fullTrustProcess’ implemented in my Excel.Interop.exe and (b) ‘windows.appService’, which I will be running in-proc with my UWP – so no need to define an entry point for this one.

<Extensions>
  <uap:Extension Category="windows.appService">
    <uap:AppService Name="ExcelInteropService" />
  </uap:Extension>
  <desktop:Extension Category="windows.fullTrustProcess"
                     Executable="Win32\Excel.Interop.exe" />
</Extensions>

 

The Excel.Interop.exe component now simply connects to our AppService and waits for requests. When the service gets closed, the component will exit.

static void Main(string[] args)
{
    // connect to app service and wait until the connection gets closed
    appServiceExit = new AutoResetEvent(false);
    InitializeAppServiceConnection();
    appServiceExit.WaitOne();
}

static async void InitializeAppServiceConnection()
{
    connection = new AppServiceConnection();
    connection.AppServiceName = "ExcelInteropService";
    connection.PackageFamilyName = Package.Current.Id.FamilyName;
    connection.RequestReceived += Connection_RequestReceived;
    connection.ServiceClosed += Connection_ServiceClosed;

    AppServiceConnectionStatus status = await connection.OpenAsync();
}

 

When a request comes in from the UWP app, we’ll handle it and do as we are told by calling the Microsoft.Office.Interop.* APIs.

private async static void Connection_RequestReceived(
   AppServiceConnection sender,
   AppServiceRequestReceivedEventArgs args)
{
    string value = args.Request.Message["REQUEST"] as string;
    string result = "";
    switch (value)
    {
        case "CreateSpreadsheet":
            try
            {
                // call Office Interop APIs to create the Excel spreadsheet
                Excel.Application excel = new Excel.Application();
                excel.Visible = true;
                Excel.Workbook wb = excel.Workbooks.Add();
                Excel.Worksheet sh = wb.Sheets.Add();
                sh.Name = "DataGrid";
                sh.Cells[1, "A"].Value2 = "Id";
                sh.Cells[1, "B"].Value2 = "Description";
                sh.Cells[1, "C"].Value2 = "Quantity";
                sh.Cells[1, "D"].Value2 = "UnitPrice";

                for (int i = 0; i < args.Request.Message.Values.Count / 4; i++)
                {
                    CreateLineItem(sh, i, args.Request.Message);
                }
                result = "SUCCESS";
            }
            catch (Exception exc)
            {
                result = exc.Message;
            }
            break;
        default:
            result = "unknown request";
            break;
    }

    ValueSet response = new ValueSet();
    response.Add("RESPONSE", result);
    await args.Request.SendResponseAsync(response);
}

 

How does the code look on the UWP client side? Very simple – once the connection is established, we can send down the content of our table (as a ValueSet) to the Excel.Interop component via the AppService connection.

private async void MainPage_AppServiceConnected(object sender, EventArgs e)
{
    // send the ValueSet to the fulltrust process
    AppServiceResponse response =
        await App.Connection.SendMessageAsync(table);

    // check the result
    object result;
    response.Message.TryGetValue("RESPONSE", out result);
    if (result.ToString() != "SUCCESS")
    {
        MessageDialog dialog = new MessageDialog(result.ToString());
        await dialog.ShowAsync();
    }
}

 

Thanks for reading this far. Hope this was helpful and you can use it to build great solutions with UWP. Questions, feedback, concerns or cheers? Please leave them in the comments or hit me up on twitter @StefanWickDev.

My BUILD2017 session – recap and next steps

I had a great time at BUILD this year, presenting with Ginny Caughey on building PC applications for Windows 10 with UWP. Ginny did amazing work creating and demonstrating the samples, and providing the perspective of Windows LOB app developers. We have received good feedback and questions after the session, please keep it coming here in the comments!

In the session we are addressing a number of gaps and myths specifically around using UWP for your desktop PC app development projects. If you haven’t seen it yet, please check out the link below and let us know your thoughts.

There is so much more in UWP that we wanted to show, but couldn’t fit into the ~50min time limit at BUILD2017. I will make an effort to get the pieces we didn’t cover in the session out on this blog in the coming weeks, and on GitHub with code samples. Also see below for a rough timeline on when the various parts we have shown will become available.

sessionsnip Click to view session on Channel9

Samples/Demos from our session:

Available now – Ginny’s first demo connecting to SQL Server via Desktop Bridge component. This also shows Compact Overlay (picture-in-picture), multi-views, drag and drop, Telerik data grid, PaymentRequest API etc.: https://github.com/Microsoft/DesktopBridgeToUWP-Samples/tree/master/Samples/SQLServer

Coming next – the command line activation and auto-launch extensions should be coming out to Windows Insiders in the next few weeks. Expect an update here on this blog and a sample on GitHub in the first half of June.

Multi-instancing – we are still designing this feature. I will have a separate update with details on this topic here as well.

SQLClient in UWP – this was Ginny’s final demo in the session, showing the UWP app accessing the SQLClient APIs directly, without Desktop Bridge – thanks to the amazing .NET Standard 2.0 work. We will share this sample on GitHub as soon as the bits from Windows, .NET and SQL are available for Insiders to consume. Stay tuned … !