UWP Features & Samples

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?

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 … !

Shape Recognition in UWP with InkAnalyzer

The SDK for the Creators Update has so many gems, but this new UWP feature from my friends on the Ink team is very near and dear to my heart: InkAnalysis is back, finally available for UWP apps!

I have spent some time working in this space back in the Windows Vista timeframe when we released the InkAnalyzer for WPF, WinForms and Win32 app. So excited to finally be able to analyze handwriting and drawing in UWP apps on all Windows 10 devices.

One of the many features of InkAnalyzer is the recognition of shapes in your ink drawings. To test it out, I dug up my WPF sample from 2007 and moved it to the new namespaces. Had to adjust a couple of API names and some of the math, but overall it was a pretty smooth port and I had things working within an hour on my PC and Phone.

ShapeRecoSample

UWP Shape Recognition anno 2017

And here is my blog post from 2007 on the same subject 🙂
https://blogs.msdn.microsoft.com/swick/2007/11/01/shape-recognition-with-wpf-and-inkanalysis/

WPFshapeReco

WPF Shape Recognition anno 2007

The Windows Store has recently started accepting Creators Update app submissions, so I was able to put my sample into the Store. Check it out on all your Win10 devices running the Creators Update:

Get it on Windows 10

The source code for this sample is available here on GitHub.

Cheers,
Stefan