Tag Archives: desktop bridge

Configure your app to start at log-in

For a long time, desktop PC users have been able to configure Win32 apps to start at startup or user log-in. This has also been possible for Desktop Bridge apps since the Windows 10 Anniversary Update (v10.0.14393.0). We’ve now extended this feature to allow regular Universal Windows Apps to take part in this also. This is available in Insider builds from Build 16226 onwards, along with the corresponding SDK. In this post, we’ll look at the code changes you need to make in your manifest and in your App class to handle the startup scenario, and how your app can work with the user to respect their choices.

Here’s a sample app, called TestStartup – the app offers a button to request enabling the startup behavior, and reports current status. Typically, you’d put this kind of option into a settings page of some kind in your app.

The first thing to note is that you must use the windows.startupTask Extension in your app manifest under the Extensions node, which is a child of the Application node. This is documented here. The same Extension declaration is used for both Desktop Bridge and regular UWP apps – but there are some differences.

  • Desktop Bridge is only available on Desktop, so it uses a Desktop-specific XML namespace. The new UWP implementation is designed for use generally on UWP, so it uses a general UAP namespace (contract version 5) – although to be clear, it is currently still only actually available on Desktop.
  • The Desktop Bridge EntryPoint must be “Windows.FullTrustApplication,” whereas for regular UWP it is the fully-qualified namespace name of your App class.
  • Desktop Bridge apps can set the Enabled attribute to true, which means that the app will start at startup without the user having to manually enable it. Conversely, for regular UWP apps this attribute is ignored, and the feature is implicitly set to “disabled.” Instead, the user must first launch the app, and the app must request to be enabled for startup activation.
  • For Desktop Bridge apps, multiple startupTask Extensions are permitted, each one can use a different Executable. Conversely, for regular UWP apps, you would have only one Executable and one startupTask Extension.
Desktop Bridge App UWP App

xmlns:desktop="http://schemas.microsoft.com/
appx/manifest/desktop/windows10"


xmlns:uap5="http://schemas.microsoft.com/
appx/manifest/uap/windows10/5"


<desktop:Extension
  Category="windows.startupTask"
  Executable="MyDesktopBridgeApp.exe"
  EntryPoint="Windows.FullTrustApplication">
  <desktop:StartupTask
    TaskId="MyStartupId"
    Enabled="false"
    DisplayName="Lorem Ipsum" />
</desktop:Extension>


<uap5:Extension
  Category="windows.startupTask"
  Executable="TestStartup.exe"
  EntryPoint="TestStartup.App">
  <uap5:StartupTask
    TaskId="MyStartupId"
    Enabled="false"
    DisplayName="Lorem Ipsum" />
</uap5:Extension>

For both Desktop Bridge apps and regular UWP apps, the user is always in control, and can change the Enabled state of your startup app at any time via the Startup tab in Task Manager:

Also for both app types, the app must be launched at least once before the user can change the Disabled/Enabled state. This is potentially slightly confusing: if the user doesn’t launch the app and then tries to change the state to Enabled in Task Manager, this will seem to be set. However, if they then close Task Manager and re-open it, they will see that the state is still Disabled. What’s happening here is that Task Manager is correctly persisting the user’s choice of the Enabled state – but this won’t actually allow the app to be activated at startup unless and until the app is launched at least once first – hence the reason it is reported as Disabled.

In your UWP code, you can request to be enabled for startup. To do this, use the StartupTask.GetAsync method to initialize a StartupTask object (documented here) – passing in the TaskId you specified in the manifest – and then call the RequestEnableAsync method. In the test app, we’re doing this in the Click handler for the button. The return value from the request is the new (possibly unchanged) StartupTaskState.


async private void requestButton_Click(object sender, RoutedEventArgs e)
{
    StartupTask startupTask = await StartupTask.GetAsync("MyStartupId");
    switch (startupTask.State)
    {
        case StartupTaskState.Disabled:
            // Task is disabled but can be enabled.
            StartupTaskState newState = await startupTask.RequestEnableAsync();
            Debug.WriteLine("Request to enable startup, result = {0}", newState);
            break;
        case StartupTaskState.DisabledByUser:
            // Task is disabled and user must enable it manually.
            MessageDialog dialog = new MessageDialog(
                "I know you don't want this app to run " +
                "as soon as you sign in, but if you change your mind, " +
                "you can enable this in the Startup tab in Task Manager.",
                "TestStartup");
            await dialog.ShowAsync();
            break;
        case StartupTaskState.DisabledByPolicy:
            Debug.WriteLine(
                "Startup disabled by group policy, or not supported on this device");
            break;
        case StartupTaskState.Enabled:
            Debug.WriteLine("Startup is enabled.");
            break;
    }
}

Because Desktop Bridge apps have a Win32 component, they run with a lot more power than regular UWP apps generally. They can set their StartupTask(s) to be Enabled in the manifest and do not need to call the API. For regular UWP apps, the behavior is more constrained, specifically:

  • The default is Disabled, so in the normal case, the user must run the app at least once explicitly – this gives the app the opportunity to request to be enabled.
  • When the app calls RequestEnableAsync, this will show a user-prompt dialog for UWP apps (or if called from a UWP component in a Desktop Bridge app from the Windows 10 Fall Creators Update onwards).
  • StartupTask includes a Disable method. If the state is Enabled, the app can use the API to set it to Disabled. If the app then subsequently requests to enable again, this will also trigger the user prompt.
  • If the user disables (either via the user prompt, or via the Task Manager Startup tab), then the prompt is not shown again, regardless of any requests from the app. The app can of course devise its own user prompts, asking the user to make manual changes in Task Manager – but if the user has explicitly disabled your startup, you should probably respect their decision and stop pestering them. In the sample code above, the app is responding to DisabledByUser by popping its own message dialog – you can obviously do this if you want, but it should be emphasized that there’s a risk you’ll just annoy the user.
  • If the feature is disabled by local admin or group policy, then the user prompt is not shown, and startup cannot be enabled. The existing StartupTaskState enum has been extended with a new value, DisabledByPolicy. When the app sees DisabledByPolicy, it should avoid re-requesting that their task be enabled, because the request will never be approved until the policy changes.
  • Platforms other than Desktop that don’t support startup tasks also report DisabledByPolicy.

Where a request triggers a user-consent prompt (UWP apps only), the message includes the DisplayName you specified in your manifest. This prompt is not shown if the state is DisabledByUser or DisabledByPolicy.

If your app is enabled for startup activation, you should handle this case in your App class by overriding the OnActivated method. Check the IActivatedEventArgs.Kind to see if it is ActivationKind.StartupTask, and if so, case the IActivatedEventArgs to a StartupTaskActivatedEventArgs. From this, you can retrieve the TaskId, should you need it. In this test app, we’re simply passing on the ActivationKind as a string to MainPage.


protected override void OnActivated(IActivatedEventArgs args)
{
    Frame rootFrame = Window.Current.Content as Frame;
    if (rootFrame == null)
    {
        rootFrame = new Frame();
        Window.Current.Content = rootFrame;
    }

    string payload = string.Empty;
    if (args.Kind == ActivationKind.StartupTask)
    { 
        var startupArgs = args as StartupTaskActivatedEventArgs;
        payload = ActivationKind.StartupTask.ToString();
    }

    rootFrame.Navigate(typeof(MainPage), payload);
    Window.Current.Activate();
}

Then, the MainPage OnNavigatedTo override tests this incoming string and uses it to report status in the UI.


protected override void OnNavigatedTo(NavigationEventArgs e)
{
    string payload = e.Parameter as string;
    if (!string.IsNullOrEmpty(payload))
    {
        activationText.Text = payload;

        if (payload == "StartupTask")
        {
            requestButton.IsEnabled = false;
            requestResult.Text = "Enabled";
            SolidColorBrush brush = new SolidColorBrush(Colors.Gray);
            requestResult.Foreground = brush;
            requestPrompt.Foreground = brush;
        }
    }
}

Note that when your app starts at startup, it will start minimized in the taskbar. In this test app, when brought to normal window mode, the app reports the ActivationKind and StartupTaskState:

Using the windows.startupTask manifest Extension and the StartupTask.RequestEnableAsync API, your app can be configured to start at user log-in. This can be useful for apps which the user expects to use heavily, and the user has control over this – but it is still a feature that you should use carefully. You should not use the feature if you don’t reasonably expect the user to want it for your app – and you should avoid repeatedly prompting them once they’ve made their choice. The inclusion of a user-prompt puts the user firmly in control, which is an improvement over the older Win32 model.

Sample Code here.

Calling WinRT Components from a Win32 process via the Desktop Bridge

In today’s post, we are covering another step you can take on your journey across the Desktop Bridge: specifically migrating business logic to Windows Runtime Components, aka WinRT Components. Previously, Windows only supported calling OS provided WinRT components from Win32 applications. Any attempt to call user-defined (aka 3rd party) WinRT components would fail because the Win32 application did not have package identity, and thus there was no way to register the component with the system at installation time, nor any way for the system to find the component at runtime.

This limitation is solved because Win32 applications on the Desktop Bridge now have identity and are registered with the OS, including any Windows Runtime Components that are part of the package. In the Windows 10 Fall Creators Update, the Desktop Bridge supports this functionality, including support for both In-Process Servers and Out-Of-Process Servers.

Code sharing – Why WinRT Components vs other options

There are many different ways to share code in your application, so what you choose depends upon your scenarios. At a high level, here are a few ways as they relate to UWP and the Desktop Bridge:

  • DLLs – for scenarios that require in-proc code performance and do not need cross-language interoperability
  • WinRT Components – for cross-language interoperability, or support out-of-process activation for reliability
  • .Net library – for scenarios that work in-proc and all clients are managed developers, including PCLs or .Net Standard libraries

Authoring new code or moving code into a Windows Runtime Component allows code reuse between the AppContainer and Win32 processes in the same package. While you can reuse existing DLLs in your AppContainer process by calling LoadPackageLibrary by moving to a Windows Runtime Component, you gain greater reusability because of better language interoperability (Native C/C++, managed code with C# & VB and Javascript) and Visual Studio integration across all your projects. Additionally, WinRT components support an out-of-process activation model that enables greater robustness for your app.

How does it work?

Because applications on the Desktop Bridge have a manifest, the registration entries for the WinRT Component are the same as you would use for a UWP application – by using the InProcessServer and OutOfProcessServer extensions. These extensions register the ActivatableClassId and its implementation binary with your package, so when your application attempts to activate the class, the system can find it.

In-Process Servers

This feature now allows developers to easily share code between Win32 apps and UWP apps running in AppContainer that can be loaded In-Proc. The component is built the same, e.g. Create a new WinRT Component project in VS, and the registration in the manifest is exactly the same as for UWP in-process servers. Because there is no manifest schema change required, developers can use existing toolsets in VS2015 or VS2017 to build In-Proc servers, but these solutions can only deploy to a machine running the latest flights of the Fall Creators Update.

Below is an example of an in-proc registration for a C++ WinRT Component, where CPPSimpleMathWinRT.dll is a native implementation of the SimpleMath class.


    <Extension Category="windows.activatableClass.inProcessServer">
      <InProcessServer>
        <Path>CPPSimpleMathWinRT.dll</Path>
        <ActivatableClass ActivatableClassId="SimpleMathWinRT.SimpleMath" ThreadingModel="both" />
      </InProcessServer>
    </Extension>

Below, you’ll see a simple Winforms Calculator sample that leverages a C++ WinRT Component for its math engine.

And this is what it looks like at runtime:

Sample with a C++/CX WinRT Component: https://github.com/Microsoft/DesktopBridgeToUWP-Samples/tree/master/Samples/WinFormsWinRTComponent

Sample with a C# WinRT Component: https://github.com/Microsoft/DesktopBridgeToUWP-Samples/tree/master/Samples/WinformsManagedWinRTComponent

Out-Of-Process servers

The registration of an OOP server for an application using the Desktop Bridge extensions is very familiar to developers who have registered servers before in UWP. However, there are details to clarify and limitations to be aware of. While OOP servers allow you to share code between your Win32 and AppContainer processes, there are limitations on sharing data between clients — that is reflected in the instancing model of the server. It all depends on your application’s needs as to which instancing model you should leverage.

The instancing behavior of a server is determined by the claims on the process token, specifically whether or not a call to NTCompareToken() for the calling process and a running instance of the server returns true. If they match, then existing instance of the server is used. If they are different, then a new instance of the server is started.

One of the key claims is the app identity. Apps in UWP are defined in the manifest and in most UWP applications submitted to the Store, there is only one App. But on the Desktop Bridge you can have more than one. Another key claim is the trust level of the calling process. On the Desktop Bridge, the package itself is declared with the runFullTrust capability, <rescap:Capability Name=”runFullTrust” />, which allows one or apps to be declared with the FullTrust entrypoint, EntryPoint=”Windows.FullTrustApplication”. Apps using the FullTrust entrypoint can call any API they want. Usually this is your main Win32/.Net executable. I’ll refer to these applications as FullTrust apps.

If you do not have this entrypoint, then the application is running in a lower trust level, called Base Trust, and has additional restrictions in a sandboxed environment called AppContainer, which is typical for an app when you create a UWP app in Visual Studio. These different trust levels result in different claims on the process tokens, and the result is a different instance of the server.  This model is called ActivateAsActivator, or AAA. An example of this registration is provided below, and you’ll note that it is the exactly same as what you’d provide for a UWP application; there is nothing new here for using this instancing model to access the server from your Win32 code:


    &amp;lt;Extension Category=&amp;quot;windows.activatableClass.outOfProcessServer&amp;quot;&amp;gt;
      &amp;lt;OutOfProcessServer ServerName=&amp;quot;Microsoft.SDKSamples.Kitchen.OvenServer&amp;quot; &amp;gt;
        &amp;lt;Path&amp;gt;Microsoft.SDKSamples.Kitchen.exe&amp;lt;/Path&amp;gt;
        &amp;lt;Instancing&amp;gt;singleInstance&amp;lt;/Instancing&amp;gt;
        &amp;lt;ActivatableClass ActivatableClassId=&amp;quot;Microsoft.SDKSamples.Kitchen.Oven&amp;quot; /&amp;gt;
      &amp;lt;/OutOfProcessServer&amp;gt;
    &amp;lt;/Extension&amp;gt;

While the ActivateAsActivator model allows you to share code, creating a separate instance of the server per client can be heavy weight. To mitigate this, UWP introduced a concept called ActivateAsPackage (AAP), which provides a single instancing behavior for servers in the package. This is reflected in the new attribute IdentityType=”activateAsPackage” on the <OutOfProcessServer> element.

There is a limitation in the AAP model however, as you must specify which trust boundary you want the server to run in. The server must be registered for use by the AppContainer processes, or for use by the FullTrust processes. If you want to use the server in both the FullTrust and AppContainer processes, you’ll need to build and register two servers with separate server names and class names, as those names need to be unique per package. To register the server for use by your FullTrust process, a new attribute RunFullTrust=”true” has been added. If you want the server to be used by your AppContainer processes, leave the attribute out.

Both new attributes are under the xmlns:uap5=”http://schemas.microsoft.com/appx/manifest/uap/windows10/5” namespace. An example registration is provided below showing both Win32 and UWP server registrations:

AAP Registration of server for use by Win32, aka FullTrust, processes:


    &amp;lt;Extension Category=&amp;quot;windows.activatableClass.outOfProcessServer&amp;quot;&amp;gt;
      &amp;lt;OutOfProcessServer ServerName=&amp;quot;Microsoft.SDKSamples.Kitchen.OvenServer&amp;quot; uap5:IdentityType=&amp;quot;activateAsPackage&amp;quot; uap5:RunFullTrust=&amp;quot;true&amp;quot;&amp;gt;
        &amp;lt;Path&amp;gt;Microsoft.SDKSamples.Kitchen.exe&amp;lt;/Path&amp;gt;
        &amp;lt;Instancing&amp;gt;singleInstance&amp;lt;/Instancing&amp;gt;
        &amp;lt;ActivatableClass ActivatableClassId=&amp;quot;Microsoft.SDKSamples.Kitchen.Oven&amp;quot; /&amp;gt;
      &amp;lt;/OutOfProcessServer&amp;gt;
    &amp;lt;/Extension&amp;gt;

AAP registration of server for use by UWP processes:


    &amp;lt;Extension Category=&amp;quot;windows.activatableClass.outOfProcessServer&amp;quot;&amp;gt;
      &amp;lt;OutOfProcessServer ServerName=&amp;quot;Microsoft.SDKSamples.Kitchen.OvenServerUWP&amp;quot; uap5:IdentityType=&amp;quot;activateAsPackage&amp;quot;&amp;gt;
        &amp;lt;Path&amp;gt;Microsoft.SDKSamples.KitchenUWP.exe&amp;lt;/Path&amp;gt;
        &amp;lt;Instancing&amp;gt;singleInstance&amp;lt;/Instancing&amp;gt;
        &amp;lt;ActivatableClass ActivatableClassId=&amp;quot;Microsoft.SDKSamples.Kitchen.OvenUWP&amp;quot; /&amp;gt;
      &amp;lt;/OutOfProcessServer&amp;gt;
    &amp;lt;/Extension&amp;gt;

The sample uses the AAP scenario and shows two C# Winforms apps using a OOP WinRT Component, resulting in only one instance of the server executable. The WinRT Component is a modified version of the WRLOutOfProcessWinRTComponent sample from the Universal Windows Samples on github. In this example, both client call the server and call the BakeBread() method. You’ll see from the TaskManager that there is only one instance of the Server.

GitHub link: https://github.com/Microsoft/DesktopBridgeToUWP-Samples/tree/master/Samples/WinformsOutOfProcessWinRTComponent

Visual Studio Support

It’s worth calling out a couple details and workarounds in projects created for this solution. First of all, Visual Studio currently does not allow you to add project references from a WinRT Component project to a Win32/.Net project.  You can work around this by unloading the Win32/.Net project and adding the project reference to the project file directly, e.g.:


  &amp;lt;ItemGroup&amp;gt;
    &amp;lt;ProjectReference Include=&amp;quot;..ServerWRLOutOfProcessWinRTComponent_server.vcxproj&amp;quot; /&amp;gt;
  &amp;lt;/ItemGroup&amp;gt;

While this adds the reference, you will see a warning in Visual Studio, as this was not previously supported by the OS. We are working with Visual Studio to improve this in a future release, but for now you can ignore the warning.

Second, the samples are using a UWP JavaScript project to handle the app packaging. This technique is noted in the Desktop Bridge Packaging with Visual Studio documentation, and works as a reasonable solution until Visual Studio adds future support. The benefit of this approach is that you can add a reference from your WinRT component to the JavaScript project, and then the Visual Studio build system adds appropriate registrations for package dependencies, including VCLibs and .NetNative, as well as the <InProcessServer> extensions. Visual Studio does not support adding registrations for <OutOfProcessServer> registrations, so you’ll need to add those manually to the manifest

Metadata Based Marshaling – No more Proxy/Stub DLLs!

Finally, in the <OutOfProcessServer> example, we take advantage of the Metadata Based Marshalling feature (MBM) that was introduced in the Windows 10 Anniversary Update (Windows 10 version 1607). This feature has not gotten much attention, but it means that WinRT Component developers do not need to author a proxy/stub class, saving them time and tedious work. This is possible because the WinMD is deployed with the application, and thus the system can identify and marshal the types cross-process for the developer. You will notice that the server code in this example does not include the proxy project nor binaries.

Conclusion

With Windows Runtime Components and the Desktop Bridge, developers can take another step on their journey to migrate business logic to UWP. Windows Runtime Components provide code re-use that can work with either FullTrust processes or UWP processes, and they allow greater interop cross language.

For more information on the Desktop Bridge, please visit the Windows Dev Center.

Ready to submit your app to the Windows Store? Let us know!

Command-Line Activation of Universal Windows Apps

As we continue to close the gap between Win32 and Universal Windows Apps, one of the features we’ve recently introduced is the ability to activate a UWA from a command line and pass the app arbitrary command-line arguments. This is available to Insiders from build 16226.

This feature builds on the App Execution Alias extension already available for Desktop Bridge apps. To use this feature in a UWA, there are two key additions to your app:

  • Add an appExecutionAlias extension to your app manifest.
  • Override OnActivated and handle the incoming arguments.

For the manifest entry, you first need to declare the XML namespace for the AppExecutionAlias element:


&amp;lt;Package
  xmlns=&amp;quot;http://schemas.microsoft.com/appx/manifest/foundation/windows10&amp;quot;
  xmlns:mp=&amp;quot;http://schemas.microsoft.com/appx/2014/phone/manifest&amp;quot;
  xmlns:uap=&amp;quot;http://schemas.microsoft.com/appx/manifest/uap/windows10&amp;quot;
  xmlns:uap5=&amp;quot;http://schemas.microsoft.com/appx/manifest/uap/windows10/5&amp;quot; 
  IgnorableNamespaces=&amp;quot;uap mp uap5&amp;quot;&amp;gt;

The AppExecutionAlias is declared as an Extension within your Application. This is quite simple and almost the same as for a Desktop Bridge app:


&amp;lt;Application ...&amp;gt;
      
  &amp;lt;Extensions&amp;gt;
      &amp;lt;uap5:Extension 
        Category=&amp;quot;windows.appExecutionAlias&amp;quot; 
        Executable=&amp;quot;MyCompany.Something.Another.exe&amp;quot; 
        EntryPoint=&amp;quot; MyCompany.Something.Another.App&amp;quot;&amp;gt;
        &amp;lt;uap5:AppExecutionAlias&amp;gt;
          &amp;lt;uap5:ExecutionAlias Alias=&amp;quot;MyApp.exe&amp;quot; /&amp;gt;
        &amp;lt;/uap5:AppExecutionAlias&amp;gt;
      &amp;lt;/uap5:Extension&amp;gt;
  &amp;lt;/Extensions&amp;gt;

&amp;lt;/Application&amp;gt;

The Executable is the name of your UWA app EXE, and the EntryPoint is the fully qualified name of your App class. The ExecutionAlias is the name that users will type in at the command-line: This can be any arbitrary name, and it must end with “.exe.” You should choose a meaningful alias that you can reasonably expect the user to associate with your app. Note that if you choose an alias that conflicts with an app that is already installed, your alias won’t be used. Similarly, if your app is installed first, and then the user installs another app later that declares the same alias – then your app will take precedence. The rule here is that the first one wins.

The manifest entry is obviously the same for VB and C++ projects, but for a JavaScript web app, it’s slightly different. Instead of Executable, you specify a StartPage, and you don’t specify EntryPoint at all:


&amp;lt;Extensions&amp;gt;
    &amp;lt;uap5:Extension 
      Category=&amp;quot;windows.appExecutionAlias&amp;quot; 
      StartPage=&amp;quot;index.html&amp;quot;&amp;gt;
      &amp;lt;uap5:AppExecutionAlias&amp;gt;
        &amp;lt;uap5:ExecutionAlias Alias=&amp;quot;MyApp.exe&amp;quot; /&amp;gt;
      &amp;lt;/uap5:AppExecutionAlias&amp;gt;
    &amp;lt;/uap5:Extension&amp;gt;
&amp;lt;/Extensions&amp;gt;

For the OnActivated override, the first thing to do is to check the ActivationKind – this is standard practice if your app supports multiple activation kinds (file associations, custom protocols and so on). In this scenario, if the ActivationKind is CommandLineLaunch, the incoming IActivatedEventArgs will be an object of type CommandLineActivatedEventArgs. From this, you can get the CommandLineActivationOperation, and from this in turn, you can get the Arguments string. You also get the CurrentDirectoryPath, which is the directory current when the command-line activation request was made. This is typically not the install location of the app itself, but could be any arbitrary path.


async protected override void OnActivated(IActivatedEventArgs args)
{
    switch (args.Kind)
    {
        case ActivationKind.CommandLineLaunch:
            CommandLineActivatedEventArgs cmdLineArgs = 
                args as CommandLineActivatedEventArgs;
            CommandLineActivationOperation operation = cmdLineArgs.Operation;
            string cmdLineString = operation.Arguments;
            string activationPath = operation.CurrentDirectoryPath;

It’s important to remember that the command-line arguments are supplied by the caller, which means that you have no control over them. You should treat these arguments as untrustworthy and parse them very carefully. They might not have any malicious intent, but they could easily be badly formed, so you need to allow for this.

After the initial checks, you can create a window as normal, and optionally pass in the (parsed and validated) command-line arguments – or some data extracted from the arguments – to that window.


            Frame rootFrame = Window.Current.Content as Frame;
            if (rootFrame == null)
            {
                rootFrame = new Frame();
                Window.Current.Content = rootFrame;
            }
            rootFrame.Navigate(typeof(MainPage), 
                string.Format(&amp;quot;CurrentDirectory={0}, Arguments={1}&amp;quot;,
                activationPath, cmdLineString));
            Window.Current.Activate();

Finally, in your page’s OnNavigatedTo, you can retrieve the payload from the event args, and use the information in any way you like:


protected override void OnNavigatedTo(NavigationEventArgs e)
{
    string cmdLineString = e.Parameter as string;
}

When you build and run the app on your dev machine – or when the end user installs your app – the  alias is registered. From that point, the user can go to a command line and activate your app.

Note that by “command line,” we mean any common command line mechanism such as cmd.exe,  powershell.exe, Windows-R and so on. Here’s a slightly more sophisticated example in which the app implements a custom parser to construct command-payload tuples from the command-line arguments:


protected override void OnActivated(IActivatedEventArgs args)
{
    switch (args.Kind)
    {
        case ActivationKind.CommandLineLaunch:
            CommandLineActivatedEventArgs cmdLineArgs = 
                args as CommandLineActivatedEventArgs;
            CommandLineActivationOperation operation = cmdLineArgs.Operation;
            string cmdLineString = operation.Arguments;
            string activationPath = operation.CurrentDirectoryPath;

            Frame rootFrame = Window.Current.Content as Frame;
            if (rootFrame == null)
            {
                rootFrame = new Frame();
                Window.Current.Content = rootFrame;
            }

            ParsedCommands parsedCommands = 
                CommandLineParser.ParseUntrustedArgs(cmdLineString);
            if (parsedCommands != null &amp;amp;&amp;amp; parsedCommands.Count &amp;gt; 0)
            {
                foreach (ParsedCommand command in parsedCommands)
                {
                    switch (command.Type)
                    {
                        case ParsedCommandType.SelectItem:
                            rootFrame.Navigate(typeof(SelectItemPage), command.Payload);
                            break;
                        case ParsedCommandType.LoadConfig:
                            rootFrame.Navigate(typeof(LoadConfigPage), command.Payload);
                            break;
                        case ParsedCommandType.Unknown:
                            rootFrame.Navigate(typeof(HelpPage), cmdLineString);
                            break;
                    }
                }
            }
            else
            {
                rootFrame.Navigate(typeof(MainPage));
            }

            Window.Current.Activate();
            break;
    }
}

The app’s logic uses these more structured commands to navigate to different pages and handle the payload in different ways. The point is that you can define whatever argument options and payload rules you like in your app.

A common scenario is testing: You can activate your app with a defined set of values for each test run – for example, to start on a particular page with boundary values set for key items – or to start a game at a particular level, with values set for player attributes, enemy count, damage levels, fuel and weaponry and so on.

If the data you provide is too long or too complex for command-line arguments, you can supply a filename on the command-line which the app can then load. One option is to include such files as content in your package (and most likely strip them out before building your release build). You can also create the files at any time later, so long as you put them in a location to which the app has access. If you want to avoid showing any filepicker UX in your app, the simplest option is to put the files in the install location for the app, which would be somewhere like %userprofile%AppDataLocalPackages<Package ID>LocalState.

You should also allow for incoming arguments that are badly formed or otherwise unrecognized:

And a reasonable UX here would be to navigate to a page where you show the user the correct usage options:

Also, bear in mind that the UWP platform has a single-instance app model. This means that your app can be running, and you can then continue to execute command-line activation requests at any point thereafter. Each activation will result in a call into OnActivated. This is unlikely to be useful in end-user scenarios of course – but it can be a useful debugging/profiling strategy during development.

Command-line activation of UWAs is just one example of how we’re gradually closing the gaps between traditional Win32 development and UWA development. This feature brings you yet another missing piece from the old world that you can now leverage in your modern apps.

UWP App Diagnostics

At Build this year, we gave a sneak preview of a set of new APIs designed to provide diagnostic information about running apps. You can see the videos here and here – but note that these were based on a pre-release implementation. So, while the Build videos are still correct on broad functionality, the final API names are almost all slightly different. Plus, we added a couple of extra features after Build.

The final versions for the upcoming release are available in the Insider builds from Build 16226, along with the corresponding SDK.

At a high level, these APIs allow an app to:

  • Enumerate a list of running apps, including UWP apps, Win32 apps, system services and so on.
  • For each app, get process-specific metrics on:
    • Memory usage (private commit and working set).
    • CPU usage.
    • Disk reads and writes.
  • For each UWP app, get additional metrics on:
    • Memory usage (including shared commit) equivalent to the Windows.System.MemoryManager report previously available to an app for its own usage.
    • State info: running, suspending, suspended, not running.
    • Energy quota info: under or over.
    • Enumerate a list of any background tasks that are active for the app, including name, trigger type and entry point.
    • Enumerate all the processes for the app (using an enhancement to the existing Windows.System.Diagnostics.ProcessDiagnosticInfo class that was previously restricted to an app for its own usage).

The API has a simple hierarchical structure:

  • The AppDiagnosticInfo type represents a single app. Callers would normally request either a single AppDiagnosticInfo for the app you’re interested in or a list of AppDiagnosticInfos if you’re interested in multiple apps.

  • Once you’ve gotten hold of an AppDiagnosticInfo for an app you’re interested in, you’d call GetResourceGroups to get a list of AppResourceGroupInfo objects. Each AppResourceGroupInfo corresponds to a resource group. An app can define resource groups in its manifest as a way to organize its components (foreground app, background tasks) into groups for resource management purposes. If you don’t define any explicit resource groups, the system will provide at least one (for the foreground app) plus potentially more (if you have out-of-proc background tasks, for example).

  • From there, you’d call any of the AppResourceGroupInfo methods to get snapshot reports of memory usage, execution and energy quota state, and the app’s running background tasks (if any) via the AppResourceGroupMemoryReport, AppResourceGroupStateReport and AppResourceGroupBackgroundTaskReport classes.

  • And finally, each group exposes a list of ProcessDiagnosticInfo objects.

As you can see from the class diagrams, the AppDiagnosticInfo and ProcessDiagnosticInfo each have a link to the other. This means you can get all the rich process-specific info for any running process and get the UWP-specific info for any process related to a UWP app (including Desktop Bridge apps).

These APIs are intended to support app developers who either need more diagnostic support during their own app development and testing, or who want to build a general-purpose diagnostic app and publish it in the Windows Store. Exposing information about other apps raises potential privacy concerns, so if your app uses these APIs, you’ll need to declare the appDiagnostics capability in your manifest, along with the corresponding namespace declaration:


&lt;Package
  xmlns:rescap=&quot;http://schemas.microsoft.com/appx/manifest/foundation/ windows10/restrictedcapabilities&quot;
  IgnorableNamespaces=&quot;uap mp rescap&quot;&gt;
  ...

  &lt;Capabilities&gt;
    &lt;rescap:Capability Name=&quot;appDiagnostics&quot; /&gt;
  &lt;/Capabilities&gt;
&lt;/Package&gt;

This is a restricted capability: If you submit an app with this capability to the Windows Store, this will trigger closer scrutiny. The app must be in the Developer Tools category, and we will examine your app to make sure that it is indeed a developer tool before approving the submission.

At run time, the capability also triggers a user-consent prompt the first time any of the diagnostic APIs are called:

The user is always in control: If permission is denied, then the APIs will only return information about the current app. The prompt is only shown on first use, but the user can change his or her mind any time via the privacy pages in Settings. All apps that use the APIs will be listed here, and the user can toggle permission either globally or on a per-app basis:

Given the richness of the APIs, it’s not too much of a stretch to envisage creating a UWP version of Task Manager. There are a few features that we can’t implement just yet (terminating apps and controlling system services, for example), but certainly most of the data reporting is perfectly possible with the new APIs:

The first thing to do is to request permission to access diagnostics for other apps using AppDiagnosticInfo.RequestAccessAsync. The result could be Denied, Limited (which means you can only get information for the current app package) or Allowed.


DiagnosticAccessStatus diagnosticAccessStatus = 
    await AppDiagnosticInfo.RequestAccessAsync();
switch (diagnosticAccessStatus)
{
    case DiagnosticAccessStatus.Allowed:
        Debug.WriteLine(&quot;We can get diagnostics for all apps.&quot;);
        break;
    case DiagnosticAccessStatus.Limited:
        Debug.WriteLine(&quot;We can only get diagnostics for this app package.&quot;);
        break;
}

Then, to emulate Task Manager, you’d start with a list of the ProcessDiagnosticInfo objects for all running processes.


IReadOnlyList&lt;ProcessDiagnosticInfo&gt; processes = ProcessDiagnosticInfo.GetForProcesses();

For each running process, you can extract the top-level process-specific information such as the ExecutableFileName and the ProcessId. You can also get the more detailed process information from each of the three reports for CpuUsage, MemoryUsage and DiskUsage.


if (processes != null)
{
    foreach (ProcessDiagnosticInfo process in processes)
    {
        string exeName = process.ExecutableFileName;
        string pid = process.ProcessId.ToString();

        ProcessCpuUsageReport cpuReport = process.CpuUsage.GetReport();
        TimeSpan userCpu = cpuReport.UserTime;
        TimeSpan kernelCpu = cpuReport.KernelTime;

        ProcessMemoryUsageReport memReport = process.MemoryUsage.GetReport();
        ulong npp = memReport.NonPagedPoolSizeInBytes;
        ulong pp = memReport.PagedPoolSizeInBytes;
        ulong peakNpp = memReport.PeakNonPagedPoolSizeInBytes;
        //...etc

        ProcessDiskUsageReport diskReport = process.DiskUsage.GetReport();
        long bytesRead = diskReport.BytesReadCount;
        long bytesWritten = diskReport.BytesWrittenCount;
        //...etc
    }
}

For any process associated with a UWP app, the IsPackaged property is true. So, for each of these, you can get from the ProcessDiagnosticInfo to the AppDiagnosticInfo. It might seem strange that we can get AppDiagnosticInfos (plural) from a process – but this is to allow for the possibility that a single process is associated with more than one app. That’s an extremely uncommon scenario, but it is possible in the case of VoIP apps where two or more apps in the same package can share a component running in a separate process at run time. In almost all cases, though, there will only be one AppDiagnosticInfo per process.


if (process.IsPackaged)
{
    IList&lt;AppDiagnosticInfo&gt; diagnosticInfos = process.GetAppDiagnosticInfos();
    if (diagnosticInfos != null &amp;&amp; diagnosticInfos.Count &gt; 0)
    {
        AppDiagnosticInfo diagnosticInfo = diagnosticInfos.FirstOrDefault();
        if (diagnosticInfo != null)
        {
            IList&lt;AppResourceGroupInfo&gt; groups = diagnosticInfo.GetResourceGroups();
            if (groups != null &amp;&amp; groups.Count &gt; 0)
            {

From the AppDiagnosticInfo, you can walk down the hierarchy and get a collection of AppResourceGroupInfos. Then, for each AppResourceGroupInfo, you can get the UWP-specific state and memory information:


AppResourceGroupInfo group = groups.FirstOrDefault();
if (group != null)
{
    string name = diagnosticInfo.AppInfo.DisplayInfo.DisplayName;
    string description = diagnosticInfo.AppInfo.DisplayInfo.Description;
    BitmapImage bitmapImage = await GetLogoAsync(diagnosticInfo);

    AppResourceGroupStateReport stateReport= group.GetStateReport();
    if (stateReport != null)
    {
        string executionStatus = stateReport.ExecutionState.ToString();
        string energyStatus = stateReport.EnergyQuotaState.ToString();
    }

    AppResourceGroupMemoryReport memoryReport = group.GetMemoryReport();
    if (memoryReport != null)
    {
        AppMemoryUsageLevel level = memoryReport.CommitUsageLevel;
        ulong limit = memoryReport.CommitUsageLimit;
        ulong totalCommit = memoryReport.TotalCommitUsage;
        ulong privateCommit = memoryReport.PrivateCommitUsage;
        ulong sharedCommit = totalCommit - privateCommit;
    }
}

Note: to get the packaged logo from the app, there’s a little extra work. You call GetLogo from the AppDisplayInfo to return the data as a stream; if there are multiple logos available, this will return the largest one that is within the specified size.


private async Task&lt;BitmapImage&gt; GetLogoAsync(AppDiagnosticInfo app)
{
    RandomAccessStreamReference stream = 
        app.AppInfo.DisplayInfo.GetLogo(new Size(64, 64));
    IRandomAccessStreamWithContentType content = await stream.OpenReadAsync();
    BitmapImage bitmapImage = new BitmapImage();
    await bitmapImage.SetSourceAsync(content);
    return bitmapImage;
}

Once you’ve collected all the various detailed metrics you’re interested in, it’s a simple matter to populate your viewmodel for data-binding purposes, to perform data analytics or to do whatever other processing you might want.

In a later post, we’ll look at how you can integrate the diagnostic APIs with existing developer tools such as Visual Studio and Appium.

How to distribute your existing Desktop Applications via Windows Store to Windows 10 PCs – including the new Windows 10 S configuration

Overview

Windows 10 S is a specific configuration of Windows 10 Pro that offers a familiar, productive Windows experience that’s streamlined for security and performance. By exclusively using apps in the Windows Store and ensuring that you browse safely with Microsoft Edge, Windows 10 S keeps you running fast and secure day in and day out. Windows 10 S was inspired by students and teachers and it’s the best Windows ever for schools. It’s also a great choice for any Windows customer looking for consistent performance and advanced security. By limiting apps to those in the Windows Store, Windows 10 S is ideal for people who have everything they need in the Windows Store and prefer the peace of mind that comes with removing the risk of downloading apps from other places.

What do I do with my existing non-Store app? Desktop Bridge is the answer

With the Desktop Bridge you can easily package your current desktop application or game as an .appx, distribute through the Windows Store and target all Windows Desktop devices including Windows 10 S to increase your user reach and easier monetization.

You can package any desktop application such as: WPF, WinForms, MFC, VB6, etc.

Once completed, your users will enjoy from smooth installation and update experiences: Clean, simple and fast install/uninstall updates via differential packages, streaming and many more.

Now you can also modernize your app with the Universal Windows Platform (UWP) to increase user engagement and reach all Windows devices.

We have a lot of customers that already went through the process such as: Kodi, Slack, Evernote, Adobe Photoshop Elements 15 and many others.

Here are few customers that shared their stories:

  1. MusiXmatch is the world’s largest lyrics platform with millions of lyrics available online and more than 50 million users on various platforms
  2. Tale of Wuxia (侠客风云传) is a traditional desktop Win32 role-playing game (RPG) that was created by Heluo Studio
  3. CLIP STUDIO PAINT is the leading paint tool software that supports creation of animation and manga

A quote from Evernote:

“The Desktop Bridge vastly simplifies our [Evernote] installer and uninstaller. It also opens up UWP APIs including Live Tiles and notifications. And having the full-featured Evernote app in the Windows Store means future improvements will reach users faster.”

—Seth Hitchings, VP Engineering, Evernote

What should I do next?

  1. Register as an app developer in the Windows Dev Center
  2. Prepare to package your application
  3. Sign up and get started using the Desktop Bridge
  4. Package your current desktop application as an .appx
  5. Test your Windows app for Windows 10 S, you can also check out this blog post for more details
  6. Submit your app to the Windows Store

Resources

Did you find this post helpful? Please let us know in the comments below—and also let us know if there’s anything else you’d like us to dig into for you about this topic.

Enjoy!

Now available: Windows Developer training course on Desktop Bridge

We are happy to announce that the Microsoft Virtual Academy training course, Developer’s Guide to the Desktop Bridge, is now available on demand.

This video course, delivered by the Desktop Bridge Program Management team, aims to help developers understand the concepts and benefits of the Desktop Bridge tooling in the Windows 10 Universal Windows Platform. Watch the video and find the relevant sample code here to start bringing your desktop apps to the Windows Store and to take advantage of new Windows 10 features of the Universal Windows Platform in your WPF, WinForms, MFC or other type of Win32 apps.

Do you want to distribute your desktop application in the Windows Store? We cover that in the course. Do you want to take advantage of modern Windows 10 app-to-app features in your existing desktop application? We cover that in the course. Do you want to light-up Windows 10 features, and still distribute your app to Windows 7 users? We cover that, too. Modernizing your desktop app gradually with UWP components? We cover all of these and more in the course.

There are eight modules:

  1. Intro to the Desktop Bridge
  2. Desktop App Converter
  3. Debugging and Testing Your Converted Apps
  4. Distributing Your Converted Apps
  5. Enhancing Desktop Applications with UWP Features
  6. Extending and Modernizing with UWP components
  7. What’s Next for the Desktop Bridge
  8. Post-Course Survey

For more information on the Desktop Bridge, please visit the Windows Dev Center.

Ready to submit your app to the Windows Store? Let us know!

Feedback or feature suggestions? Submit them on User Voice.

ICYMI – Your weekly TL;DR

Building a new app this weekend? Check out last week’s Windows Developer updates before you dive in.

COM Server and OLE Document support for the Desktop Bridge

The Windows 10 Creators Update adds out-of-process (OOP) COM and OLE support for apps on the Desktop Bridge – a.k.a Packaged COM. Read more here to find out how it works.

Visual Studio 2017 – Now Ready for Your Windows Application Development Needs

Visual Studio 2017 is the most powerful Universal Windows Platform development environment. It brings unparalleled productivity improvements, a streamlined acquisition experience and enhanced debugging tools for UWP devs. Check it out.

Monetizing your app: Advertisement placement

App developers are free to place their ads in any part of their apps and many have done so to blend the ad experience into their app. We have seen that devs who take the time to do this get the best performance for their ads and earn more revenue. Want to learn how they do it?

The new Djay Pro App for Windows

Download Visual Studio to get started.

The Windows team would love to hear your feedback. Please keep the feedback coming using our Windows Developer UserVoice site. If you have a direct bug, please use the Windows Feedback tool built directly into Windows 10.

COM Server and OLE Document support for the Desktop Bridge

The Windows 10 Creators Update adds out-of-process (OOP) COM and OLE support for apps on the Desktop Bridge – a.k.a Packaged COM. Historically, Win32 apps would create COM extensions that other applications could use. For example, Microsoft Excel exposes its Excel.Application object so third-party applications can automate operations in Excel, leveraging its rich object model. But in the initial release of the Desktop Bridge with the Windows 10 Anniversary Update, an application cannot expose its COM extension points, as all registry entries are in its private hive and not exposed publicly to the system. Packaged COM provides a mechanism for COM and OLE entries to be declared in the manifest so they can be used by external applications. The underlying system handles the activation of the objects so they can be consumed by COM clients – all while still delivering on the Universal Windows Platform (UWP) promise of having a no-impact install and uninstall behavior.

How it works

Packaged COM entries are read from the manifest and stored in a new catalog that the UWP deployment system manages. This solves one of the main problems in COM in which any application or installer can write to the registry and corrupt the system, e.g. overwriting existing COM registrations or leaving behind registry entries upon uninstall.

At run-time when a COM call is made, i.e. calling CLSIDFromProgID() or CoCreateInstance(), the system first looks in the Packaged COM catalog and, if not found, falls back to the system registry. The COM server is then activated and runs OOP from the client application.

When to use Packaged COM

Packaged COM is very useful for apps that expose third-party extension points, but not all applications need it. If your application uses COM only for its own personal use, then you can rely on COM entries in the application’s private hive (Registry.dat) to support your app. All binaries in the same package have access to that registry, but any other apps on the system cannot see into your app’s private hive. Packaged COM allows you explicit control over which servers can be made public and used by third-parties.

Limitations

As the Packaged COM entries are stored in a separate catalog, applications that directly read the registry (e.g. calling RegOpenKeyEx() or RegEnumKeyEx()) will not see any entries and will fail. In these scenarios, applications providing extensions will need to work with their partners to go through COM API calls or provide another app-to-app communication mechanism.

Support is scoped to OOP servers, allowing two key requirements. First, OOP server supports means the Desktop Bridge can maintain its promise of serviceability. By running extensions OOP, the update manager can shut down the COM server and update all binaries because there are no dlls in use loaded by other processes. Second, OOP allows for a more robust extension mechanism. If an in-process COM server is hung, it will also hang the app; for OOP, the host app will still function and can decide how to handle the misbehaving OOP server.

We do not support every COM and OLE registration entry, for the full list of what we support please refer to the element hierarchy in the Windows 10 app package manifest on MSDN: https://docs.microsoft.com/uwp/schemas/appxpackage/uapmanifestschema/root-elements

Taking a closer look

The keys to enabling this functionality are the new manifest extension categories “windows.comServer” and “windows.comInterface.” The “windows.comServer” extension corresponds to the typical registration entries found under the CLSID (i.e.  HKEY_CLASSES_ROOTCLSID{MyClsId}) for an application supporting executable servers and their COM classes (including their OLE registration entries), surrogate servers, ProgIDs and TreatAs classes. The “windows.comInterface” extension corresponds to the typical registration entries under both the HKCR Interface{MyInterfaceID} and HKCRTypelib{MyTypelibID}, and supports Interfaces, ProxyStubs and Typelibs.

If you have registered COM classes before, these elements will look very familiar and straightforward to map from the existing registry keys into manifest entries. Here are a few examples.

Example #1: Registering an .exe COM server

In this first example, we will package ACDual for the Desktop Bridge. ACDual is an MFC OLE sample that shipped in earlier versions of Visual Studio. This app is an .exe COM server, ACDual.exe, with a Document CoClass that implements the IDualAClick interface. A client can then consume it. Below is a picture of the ACDual server and a simple WinForms client app that is using it:

Fig. 1 Client WinForms app automating AutoClick COM server

Store link: https://www.microsoft.com/store/apps/9nm1gvnkhjnf

GitHub link: https://github.com/Microsoft/DesktopBridgeToUWP-Samples/tree/master/Samples/PackagedComServer

Registry versus AppxManifest.xml

To understand how Packaged COM works, it helps to compare the typical entries in the registry with the Packaged COM entries in the manifest. For a minimal COM server, you typically need a CLSID with the LocalServer32 key, and an Interface pointing to the ProxyStub to handle cross-process marshaling. ProgIDs and TypeLibs make it easier to read and program against. Let’s take a look at each section and compare what the system registry looks like in comparison to Packaged COM snippets. First, let’s look at the following ProgID and CLSID entry that registers a server in the system registry:


; ProgID registration
[HKEY_CLASSES_ROOTACDual.Document]
@=&amp;quot;AClick Document&amp;quot;
[HKEY_CLASSES_ROOTACDual.DocumentCLSID]
@=&amp;quot;{4B115281-32F0-11CF-AC85-444553540000}&amp;quot;
[HKEY_CLASSES_ROOTACDual.DocumentDefaultIcon]
@=”C:VCSamplesMFColeacdualReleaseACDual.exe,1”

; CLSID registration
[HKEY_CLASSES_ROOTCLSID{4B115281-32F0-11CF-AC85-444553540000}]
@=&amp;quot;AClick Document&amp;quot;
[HKEY_CLASSES_ROOTCLSID{4B115281-32F0-11CF-AC85-444553540000}InprocHandler32]
@=&amp;quot;ole32.dll&amp;quot;
[HKEY_CLASSES_ROOTCLSID{4B115281-32F0-11CF-AC85-444553540000}LocalServer32]
@=&amp;quot;&amp;quot;C:VCSamplesMFColeacdualReleaseACDual.exe&amp;quot;&amp;quot;
[HKEY_CLASSES_ROOTCLSID{4B115281-32F0-11CF-AC85-444553540000}ProgID]
@=&amp;quot;ACDual.Document&amp;quot;

For comparison, the translation into the package manifest is straightforward. The ProgID and CLSID are supported through the windows.comServer extension, which must be under your app’s Application element along with all of your other extensions. Regarding ProgIDs, you can have multiple ProgID registrations for your server. Notice that there is no default value of the ProgID to provide a friendly name, as that information is stored with the CLSID registration and one of the goals of the manifest schema is to reduce duplication of information. The CLSID registration is enabled through the ExeServer element with an Executable attribute, which is a relative path to the .exe contained in the package. Package-relative paths solve one common problem with registering COM servers declaratively: in a .REG file, you don’t know where your executable is located. Often in a package, all the files are placed in the root of the package. The Class registration element is within the ExeServer element. You can specify one or more classes for an ExeServer.


&amp;lt;Applications&amp;gt;
    &amp;lt;Application Id=&amp;quot;ACDual&amp;quot; Executable=&amp;quot;ACDual.exe&amp;quot; EntryPoint=&amp;quot;Windows.FullTrustApplication&amp;quot;&amp;gt;
      &amp;lt;uap:VisualElements DisplayName=&amp;quot;ACDual&amp;quot; .../&amp;gt;
    &amp;lt;Extensions&amp;gt;      
      &amp;lt;com:Extension Category=&amp;quot;windows.comServer&amp;quot;&amp;gt;
        &amp;lt;com:ComServer&amp;gt;
          &amp;lt;!-- CLSID --&amp;gt;
          &amp;lt;com:ExeServer Executable=&amp;quot;ACDual.exe&amp;quot; DisplayName=&amp;quot;AutoClick&amp;quot;&amp;gt;
            &amp;lt;com:Class Id =&amp;quot;4B115281-32F0-11cf-AC85-444553540000&amp;quot; DisplayName=&amp;quot;AClick Document&amp;quot; ProgId=&amp;quot;AutoClick.Document.1&amp;quot; VersionIndependentProgId=&amp;quot;AutoClick.Document&amp;quot;&amp;gt;
            &amp;lt;/com:Class&amp;gt;                       
          &amp;lt;/com:ExeServer&amp;gt;      
          &amp;lt;!-- ProgId --&amp;gt;
          &amp;lt;com:ProgId Id=&amp;quot;AutoClick.Document&amp;quot; CurrentVersion=&amp;quot;AutoClick.Document.1&amp;quot; /&amp;gt;
          &amp;lt;com:ProgId Id=&amp;quot;AutoClick.Document.1&amp;quot; Clsid=&amp;quot;4B115281-32F0-11cf-AC85-444553540000&amp;quot; /&amp;gt;
        &amp;lt;/com:ComServer&amp;gt;
      &amp;lt;/com:Extension&amp;gt;

The next step is TypeLib and interface registration. In this example, the TypeLib is part of the main executable, and the interface uses the standard marshaler (oleaut32.dll) for its ProxyStub, so the registration is as follows:


[HKEY_CLASSES_ROOTInterface{0BDD0E81-0DD7-11CF-BBA8-444553540000}]
@=&amp;quot;IDualAClick&amp;quot;
[HKEY_CLASSES_ROOTInterface{0BDD0E81-0DD7-11CF-BBA8-444553540000}ProxyStubClsid32]
@=&amp;quot;{00020424-0000-0000-C000-000000000046}&amp;quot;
[HKEY_CLASSES_ROOTInterface{0BDD0E81-0DD7-11CF-BBA8-444553540000}TypeLib]
@=&amp;quot;{4B115284-32F0-11CF-AC85-444553540000}&amp;quot;
&amp;quot;Version&amp;quot;=&amp;quot;1.0&amp;quot;


;TypeLib registration
[HKEY_CLASSES_ROOTTypeLib{4B115284-32F0-11CF-AC85-444553540000}]
[HKEY_CLASSES_ROOTTypeLib{4B115284-32F0-11CF-AC85-444553540000}1.0]
@=&amp;quot;ACDual&amp;quot;
[HKEY_CLASSES_ROOTTypeLib{4B115284-32F0-11CF-AC85-444553540000}1.0]
[HKEY_CLASSES_ROOTTypeLib{4B115284-32F0-11CF-AC85-444553540000}1.0win32]
@=&amp;quot; C:VCSamplesMFColeacdualReleaseAutoClik.TLB&amp;quot;
[HKEY_CLASSES_ROOTTypeLib{4B115284-32F0-11CF-AC85-444553540000}1.0FLAGS]
@=&amp;quot;0&amp;quot;
[HKEY_CLASSES_ROOTTypeLib{4B115284-32F0-11CF-AC85-444553540000}1.0HELPDIR]
@=&amp;quot;&amp;quot;

In translating this into the package manifest, the windows.comInterface extension supports one or more TypeLib, ProxyStub and interface registrations. Typically, it is placed under the Application element so it is easier to associate with the class registrations for readability, but it may also reside under the Package element. Also, note that we did not have to remember the CLSID of the universal marshaler (the key where ProxyStubClsid32 = {00020424-0000-0000-C000-000000000046}). This is simply a flag: UseUniversalMarshaler=”true”.


&amp;lt;com:Extension Category=&amp;quot;windows.comInterface&amp;quot;&amp;gt;
        &amp;lt;com:ComInterface&amp;gt;
          &amp;lt;!-- Interfaces --&amp;gt;
          &amp;lt;!-- IID_IDualAClick --&amp;gt;
          &amp;lt;com:Interface Id=&amp;quot;0BDD0E81-0DD7-11cf-BBA8-444553540000&amp;quot; UseUniversalMarshaler=&amp;quot;true&amp;quot;&amp;gt;
            &amp;lt;com:TypeLib Id=&amp;quot;4B115284-32F0-11cf-AC85-444553540000&amp;quot; VersionNumber=&amp;quot;1.0&amp;quot; /&amp;gt;
          &amp;lt;/com:Interface&amp;gt;

          &amp;lt;!-- TypeLib --&amp;gt;
          &amp;lt;com:TypeLib Id=&amp;quot;4B115284-32F0-11cf-AC85-444553540000&amp;quot;&amp;gt;
            &amp;lt;com:Version DisplayName = &amp;quot;ACDual&amp;quot; VersionNumber=&amp;quot;1.0&amp;quot; LocaleId=&amp;quot;0&amp;quot; LibraryFlag=&amp;quot;0&amp;quot;&amp;gt;
              &amp;lt;com:Win32Path Path=&amp;quot;AutoClik.tlb&amp;quot; /&amp;gt;
            &amp;lt;/com:Version&amp;gt;
          &amp;lt;/com:TypeLib&amp;gt;
        &amp;lt;/com:ComInterface&amp;gt;
      &amp;lt;/com:Extension&amp;gt;
    &amp;lt;/Extensions&amp;gt;
    &amp;lt;/Application&amp;gt;
  &amp;lt;/Applications&amp;gt;

Now you can initialize and use the server from any language that supports COM and dual interface OLE automation servers.

Example #2: OLE support

In this next example, we will package an existing OLE document server to demonstrate the capabilities of the Desktop Bridge and Packaged COM. The example we will use is the MFC Scribble sample app, which provides an insertable document type called Scribb Document. Scribble is a simple server that allows an OLE container, such as WordPad, to insert a Scribb Document.

Fig 2. WordPad hosting an embedded Scribb Document

Store Link: https://www.microsoft.com/store/apps/9n4xcm905zkj

GitHub Link: https://github.com/Microsoft/DesktopBridgeToUWP-Samples/tree/master/Samples/PackagedOleDocument

Registry versus AppxManifest.xml

There are many keys to specify various OLE attributes. Again, the magic here is that the platform has been updated to work with Packaged COM, and all you have to do is translate those keys into your manifest. In this example, the entries for Scribble include the ProgID, its file type associations and the CLSID with entries.


;SCRIBBLE.REG
;
;FileType Association using older DDEExec command to launch the app
[HKEY_CLASSES_ROOT.SCB]
@=”Scribble.Document”
[HKEY_CLASSES_ROOTScribble.Documentshellopencommand]
@=”SCRIBBLE.EXE %1”


;ProgId
[HKEY_CLASSES_ROOTScribble.Document]
@= Scribb Document
[HKEY_CLASSES_ROOTScribble.DocumentInsertable]
@=””
[HKEY_CLASSES_ROOTScribble.DocumentCLSID]
@= “{7559FD90-9B93-11CE-B0F0-00AA006C28B3}}”


;ClsId with OLE entries
[HKEY_CLASSES_ROOTCLSID{7559FD90-9B93-11CE-B0F0-00AA006C28B3}]
@=&amp;quot;Scribb Document&amp;quot;
[HKEY_CLASSES_ROOTCLSID{7559FD90-9B93-11CE-B0F0-00AA006C28B3}AuxUserType]
[HKEY_CLASSES_ROOTCLSID{7559FD90-9B93-11CE-B0F0-00AA006C28B3}AuxUserType2]
@=&amp;quot;Scribb&amp;quot;
[HKEY_CLASSES_ROOTCLSID{7559FD90-9B93-11CE-B0F0-00AA006C28B3}AuxUserType3]
@=&amp;quot;Scribble&amp;quot;
[HKEY_CLASSES_ROOTCLSID{7559FD90-9B93-11CE-B0F0-00AA006C28B3}DefaultIcon]
@=&amp;quot;&amp;quot;C:VC2015SamplesscribbleReleaseScribble.exe&amp;quot;,1&amp;quot;
[HKEY_CLASSES_ROOTCLSID{7559FD90-9B93-11CE-B0F0-00AA006C28B3}InprocHandler32]
@=&amp;quot;ole32.dll&amp;quot;
[HKEY_CLASSES_ROOTCLSID{7559FD90-9B93-11CE-B0F0-00AA006C28B3}Insertable]
@=&amp;quot;&amp;quot;
[HKEY_CLASSES_ROOTCLSID{7559FD90-9B93-11CE-B0F0-00AA006C28B3}LocalServer32]
@=&amp;quot;&amp;quot;C:VC2015SamplesscribbleReleaseScribble.exe&amp;quot;&amp;quot;
[HKEY_CLASSES_ROOTCLSID{7559FD90-9B93-11CE-B0F0-00AA006C28B3}MiscStatus]
@=&amp;quot;32&amp;quot;
[HKEY_CLASSES_ROOTCLSID{7559FD90-9B93-11CE-B0F0-00AA006C28B3}ProgID]
@=&amp;quot;Scribble.Document&amp;quot;
[HKEY_CLASSES_ROOTCLSID{7559FD90-9B93-11CE-B0F0-00AA006C28B3}Verb]
[HKEY_CLASSES_ROOTCLSID{7559FD90-9B93-11CE-B0F0-00AA006C28B3}Verb]
@=&amp;quot;&amp;amp;amp;Edit,0,2&amp;quot;
[HKEY_CLASSES_ROOTCLSID{7559FD90-9B93-11CE-B0F0-00AA006C28B3}Verb1]
@=&amp;quot;&amp;amp;amp;Open,0,2&amp;quot;

First, let’s discuss the file type association. This is an extension that was supported in the first release of the Desktop Bridge extensions. Note that specifying the file type association here automatically adds support for the shell open command.

Next, let’s take a closer look at the ProgID and CLSID entries. In this case, the simple example only has a ProgID and no VersionIndependentProgID.

Most of the excitement in this example is underneath the CLSID where all the OLE keys live. The registry keys typically map to attributes of the class, such as:

  • Insertable key under either the ProgID or CLSID, mapping to the InsertableObject=”true” attribute
  • If the InprocHandler32 key is Ole32.dll, use the EnableOleDefaultHandler=”true” attribute
  • AuxUserType2, mapping to ShortDisplayName
  • AuxUserType3, mapping to the Application DisplayName
  • In cases where there were multiple values in a key, such as the OLE verbs, we’ve split those out into separate attributes. Here’s what the full manifest looks like:
&amp;lt;Applications&amp;gt;
&amp;lt;Application Id=&amp;quot;Scribble&amp;quot; Executable=&amp;quot;Scribble.exe&amp;quot; EntryPoint=&amp;quot;Windows.FullTrustApplication&amp;quot;&amp;gt;
&amp;lt;uap:VisualElements DisplayName=&amp;quot;Scribble App&amp;quot; .../&amp;gt;
&amp;lt;Extensions&amp;gt;
&amp;lt;uap:Extension Category=&amp;quot;windows.fileTypeAssociation&amp;quot;&amp;gt;
&amp;lt;uap3:FileTypeAssociation Name=&amp;quot;scb&amp;quot; Parameters=&amp;quot;%1&amp;quot;&amp;gt;
&amp;lt;uap:SupportedFileTypes&amp;gt;
&amp;lt;uap:FileType&amp;gt;.scb&amp;lt;/uap:FileType&amp;gt;
&amp;lt;/uap:SupportedFileTypes&amp;gt;
&amp;lt;/uap3:FileTypeAssociation&amp;gt;
&amp;lt;/uap:Extension&amp;gt;
&amp;lt;com:Extension Category=&amp;quot;windows.comServer&amp;quot;&amp;gt;
&amp;lt;com:ComServer&amp;gt;
&amp;lt;com:ExeServer Executable=&amp;quot;Scribble.exe&amp;quot; DisplayName=&amp;quot;Scribble&amp;quot;&amp;gt;
&amp;lt;!-- ClsId Registration --&amp;gt;
&amp;lt;com:Class Id=&amp;quot;7559FD90-9B93-11CE-B0F0-00AA006C28B3&amp;quot; DisplayName=&amp;quot;Scribb Document&amp;quot; ShortDisplayName=&amp;quot;Scribb&amp;quot; ProgId=&amp;quot;Scribble.Document.1&amp;quot; VersionIndependentProgId =&amp;quot;Scribble.Document&amp;quot; EnableOleDefaultHandler=&amp;quot;true&amp;quot; InsertableObject=&amp;quot;true&amp;quot;&amp;gt;
&amp;lt;com:DefaultIcon Path=&amp;quot;Scribble.exe&amp;quot; ResourceIndex=&amp;quot;1&amp;quot; /&amp;gt;
&amp;lt;com:MiscStatus OleMiscFlag=&amp;quot;32&amp;quot;/&amp;gt;
&amp;lt;com:Verbs&amp;gt;
&amp;lt;com:Verb Id=&amp;quot;0&amp;quot; DisplayName=&amp;quot;&amp;amp;amp;Edit&amp;quot; AppendMenuFlag=&amp;quot;0&amp;quot; OleVerbFlag=&amp;quot;2&amp;quot; /&amp;gt;
&amp;lt;com:Verb Id=&amp;quot;1&amp;quot; DisplayName=&amp;quot;&amp;amp;amp;Open&amp;quot; AppendMenuFlag=&amp;quot;0&amp;quot; OleVerbFlag=&amp;quot;2&amp;quot; /&amp;gt;
&amp;lt;/com:Verbs&amp;gt;
&amp;lt;/com:Class&amp;gt;
&amp;lt;/com:ExeServer&amp;gt;
&amp;lt;!-- ProgId Registration --&amp;gt;
&amp;lt;com:ProgId Id=&amp;quot;Scribble.Document&amp;quot; CurrentVersion=&amp;quot;Scribble.Document.1&amp;quot; /&amp;gt;
&amp;lt;com:ProgId Id=&amp;quot;Scribble.Document.1&amp;quot; Clsid=&amp;quot;7559FD90-9B93-11CE-B0F0-00AA006C28B3&amp;quot; /&amp;gt;
&amp;lt;/com:ComServer&amp;gt;
&amp;lt;/com:Extension&amp;gt;
&amp;lt;/Extensions&amp;gt;
&amp;lt;/Application&amp;gt;
&amp;lt;/Applications&amp;gt;

Additional support

The two examples above covered the most common cases of a COM server and an OLE document support. Packaged COM also supports additional servers like Surrogates and TreatAs classes. For more information, please refer to the element hierarchy in the Windows 10 app package manifest on MSDN: https://docs.microsoft.com/uwp/schemas/appxpackage/uapmanifestschema/root-elements

Conclusion

With UWP and Windows 10, applications can take advantage of several exciting new features while leveraging existing code investments in areas such as COM. With the Desktop Bridge platform and tooling enhancements, existing PC software can now be part of the UWP ecosystem and take advantage of the same set of new platform features and operating system capabilities.

For more information on the Desktop Bridge, please visit the Windows Dev Center.

Ready to submit your app to the Windows Store? Let us know!

Windows 10 Creators Update and Creators Update SDK are Released

This is a big day! Today we opened access to download the Windows 10 Creators Update and, along with it, the Creators Update SDK. And today is a great day for all Windows developers to get the SDK and start building amazing apps that take advantage of new platform capabilities to deliver experiences that you and your users will love.

We are working hard to innovate in Windows and to bring the power of those innovations to Windows developers and users. We released Windows 10 Anniversary Update just eight months ago, and we’ve already seen that over 80% of Windows 10 PCs are running Anniversary Update (version 1607) or later.

With today’s release of Windows 10 Creators Update, we expect users to once again move rapidly to the latest and best version of Windows. For developers, this is the time to get ready for the next wave.

What’s New in the Creators Update

Here are just a few of the new and powerful capabilities in the Creators Update:

  • Enhancements to the visual layer (effects, animations and transitions) and elevation of many effects to the XAML layer with improved controls that make the enhancements easy to bring to apps
  • Improvements to ink, including ink analysis and improved recognition, and an ink toolbar with new effects (tilt pencil) and tools (protractor for drawing curves and circles)
  • More powerful and flexible APIs for the Surface Dial
  • Significant Bluetooth improvements with Bluetooth LE GATT Server, peripheral mode for easier discovery of Windows Devices, and support for loosely coupled Bluetooth devices (those low energy devices that do not have to be explicitly paired)
  • Better user engagement via notifications that can now be grouped by app, bind to data and contain in-line controls such as progress bars
  • Improvements to the Desktop Bridge to make it easier than ever to bring Win32 apps to Windows 10 and the Windows Store
  • The ability to have seamless cross-device experiences with Project Rome and the recently released Android SDK for Project Rome
  • More targeted and effective user acquisition via Facebook app install ads with the Windows SDK for Facebook
  • Background execution enhancements that enable tasks to do more with increased memory and time
  • Enhanced security for apps with the ability to integrate Windows Hello
  • Richer app analytics via an updated Dev Portal that enables management of multiple apps and enhanced reporting
  • Faster app downloads and updates with the ability to componentize app packages and do streaming installs
  • Increased efficiency and flexibility with the new ability in Visual Studio 2017 to run two different SDK versions side by side on the same machine
  • Significant improvements to the Windows Console and the Windows Subsystem for Linux enabling many of the most used Linux frameworks, tools and services
  • New and natural ways for users to connect and engage with apps using the Cortana Skills Kit
  • The ability for game developers to reach new audiences by publishing UWP games on the Xbox via the Xbox Live Creators Program
  • Amazing 3D experiences on HoloLens and new mixed reality headsets via the Windows Mixed Reality Platform

You can find a more complete list here along with the latest developer documentation.

We’ll be taking a close look at all of these (and a lot more) at Microsoft Build 2017, including some of the things we’ve got planned for the future.

I hope to see you there!

Get Started Now

To get started, please check out Clint Rutkas’ post for the details on how to get the latest version of Visual Studio and the SDK. And take a look at Daniel Jacobson’s blog post to see some of the improvements for UWP developers in Visual Studio 2017.

— Kevin

Desktop Bridge: Creators Update

Overview

The Creators Update is packed with new features for app developers and end users that are designed to delight developers who can offer their end users a rich experience.

User transition & data migration

Users are encouraged to download the store version of their desktop apps. If the user already has the previous desktop version of the app, the transition experience is as seamless as possible.

As a result, the Creators Update will provides a smooth transition along with some best practices for app developers to follow.

For a detailed blog post on this topic with code samples, please see this blog post.

User transition: taskbar pins & start tiles

Many users typically pin their favorite or most used apps to the taskbar pin or the start menu so they can access apps quickly.

With the Creators Update, app developers can re-route the taskbar pins and the start tile shortcuts to point to the store version of the desktop app.

User transition: file type associations & protocol handlers

The user may choose their favorite app to be the default app for a given file type or protocol. With the Creators Update, the developers can also transition the user’s choice to use the store version of the same app.

Data migration

As best practice, it is recommended that developers attempt to migrate previous user data from the desktop app upon first launch of the store version of the same app.

Users will love that they can pick up where they left off.

User transition: uninstall previous desktop app

As best practice, developers should offer uninstallation of the previous desktop app upon first launch of the store version of the app. This helps in avoiding user confusion and potential user data corruption.

Keep in mind the user can refuse the uninstallation of the previous desktop app, so the previous and store version of the app may end up running side-by-side. It is up to the app developer to decide whether or not to block the launch of the store version of the app until the previous desktop app is uninstalled.

Windows Explorer delight: previews, thumbnails, detailed properties and grouping by kind

Another focus of the Creators Update release was on user satisfaction.

Store versions of desktop apps can now take advantage of Windows Explorer perks to lead users to more frequently engage with their apps.

Preview handler

Preview handlers are triggered when an item is selected to show a lightweight, rich, read-only preview of the file’s contents in the view’s reading pane. You can do this without launching the file’s associated application.

XML sample:

&lt;Extensions&gt;
&lt;Extension Category=&quot;windows.fileTypeAssociation&quot;&gt;
&lt;FileTypeAssociation Name=&quot;Foo&quot;&gt;
&lt;SupportedFileTypes&gt;
&lt;FileType&gt;.bar&lt;/FileType&gt;
&lt;/SupportedFileTypes&gt;
&lt;DesktopPreviewHandler CLSID=&quot;20000000-0000-0000-0000-000000000001&quot; /&gt;
&lt;/FileTypeAssociation&gt;
&lt;/Extension&gt;
&lt;/Extensions&gt;

Thumbnail handler

In Windows Explorer, thumbnails can provide a read-only view inside the file when the viewing is set to medium icons or higher.

XML sample:

&lt;Extensions&gt;
&lt;Extension Category=&quot;windows.fileTypeAssociation&quot;&gt;
&lt;FileTypeAssociation Name=&quot;Foo&quot;&gt;
&lt;SupportedFileTypes&gt;
&lt;FileType&gt;.bar&lt;/FileType&gt;
&lt;/SupportedFileTypes&gt;
&lt;ThumbnailHandler CLSID=&quot;20000000-0000-0000-0000-000000000001&quot; Cutoff=&quot;20x20&quot; Treatment=&quot;Video Sprockets&quot; /&gt;
&lt;/FileTypeAssociation&gt;
&lt;/Extension&gt;
&lt;/Extensions&gt;

Property handler

Microsoft Windows Search uses property handlers to extract the values of properties from items, and uses the property system schema to determine how a specific property should be indexed. In addition, property handlers can be used to provide more details about a certain file in the properties dialog or in the details pane.

XML sample:

&lt;Extensions&gt;
&lt;Extension Category=&quot;windows.fileTypeAssociation&quot;&gt;
&lt;FileTypeAssociation Name=&quot;Foo&quot;&gt;
&lt;SupportedFileTypes&gt;
&lt;FileType&gt;.bar&lt;/FileType&gt;
&lt;/SupportedFileTypes&gt;
&lt;DesktopPropertyHandler CLSID=&quot;20000000-0000-0000-0000-000000000001&quot; /&gt;
&lt;/FileTypeAssociation&gt;
&lt;/Extension&gt;
&lt;/Extensions&gt;

Grouping files by their ‘kind’

Developers can specify what ‘kind’ their file types are, which will enable the end users to group their files by their ‘kind’ in Windows Explorer.

XML sample:

&lt;uap:Extension Category=&quot;windows.fileTypeAssociation&quot;&gt;
&lt;uap:FileTypeAssociation Name=&quot;scoobydoo&quot;&gt;
&lt;uap:SupportedFileTypes&gt;
&lt;uap:FileType&gt;.m4a&lt;/uap:FileType&gt;
&lt;uap:FileType&gt;.mta&lt;/uap:FileType&gt;
&lt;/uap:SupportedFileTypes&gt;
&lt;rescap:KindMap&gt;
&lt;rescap:Kind value=&quot;Item&quot; /&gt;
&lt;rescap:Kind value=&quot;Communications&quot; /&gt;
&lt;rescap:Kind value=&quot;Task&quot; /&gt;
&lt;/rescap:KindMap&gt;
&lt;/uap:FileTypeAssociation&gt;
&lt;/uap:Extension&gt;

Support for custom fonts installation by apps

Microsoft Windows Store apps can share their custom fonts with other Windows applications. This is done by making a few simple edits to the application manifest.

XML sample:

&lt;Extensions&gt;
&lt;uap4:Extension Category=&quot;windows.sharedFonts&quot;&gt;
&lt;uap4:SharedFonts&gt;
&lt;uap4:Font File=&quot;FontsJustRealize.ttf&quot; /&gt;
&lt;uap4:Font File=&quot;FontsJustRealizeBold.ttf&quot; /&gt;
&lt;/uap4:SharedFonts&gt;
&lt;/uap4:Extension&gt;
&lt;/Extensions&gt;

Public out-of-process COM server support, aka Packaged COM

Developers can now add support for out-of-process COM and OLE extensions support for store version of desktop apps. This technology is referred to as Packaged COM. Historically, desktop apps created COM extensions that other applications could use. However, in the Windows 10 Anniversary Update release of Desktop Bridge, an application cannot expose its COM extension points as all registry entries are in its private hive and not exposed publicly to the system. Packaged COM provides a mechanism for COM and OLE entries to be declared in the manifest while the underlying subsystem handles the activation of the objects while still providing no-impact install behavior.

Firewall Rules

When apps need the users to add the app as an exception to the firewall, it translates into user confusion, additional user clicks and/or denial of exception by mistake.

The Windows Security Alert tries to educate the user, but it’s still one more decision the user must make before they can use their app.

In addition, subsequent app updates will result in the same dialog pop up and take the user through the same flow.

With the Creators Update, the developers can register for firewall rules ahead of time, so the users don’t have to make a firewall choice prior to launching their apps (including after subsequent app updates).

XML sample:

&lt;Extensions&gt;
&lt;desktop2:Extension Category=&quot;windows.firewallRules&quot;&gt;
&lt;desktop2:FirewallRules Executable=&quot;foo.exe&quot;&gt;
&lt;desktop2:Rule Direction=&quot;in&quot; IPProtocol=&quot;TCP&quot; Profile=&quot;all&quot;/&gt;
&lt;desktop2:Rule Direction=&quot;in&quot; IPProtocol=&quot;UDP&quot; LocalPortMin=&quot;1337&quot; LocalPortMax=&quot;1338&quot; Profile=&quot;domain&quot;/&gt;
&lt;desktop2:Rule Direction=&quot;in&quot; IPProtocol=&quot;UDP&quot; LocalPortMin=&quot;1337&quot; LocalPortMax=&quot;1338&quot; Profile=&quot;public&quot;/&gt;
&lt;desktop2:Rule Direction=&quot;out&quot; IPProtocol=&quot;UDP&quot; LocalPortMin=&quot;1339&quot; LocalPortMax=&quot;1340&quot; RemotePortMin=&quot;15&quot; RemotePortMax=&quot;19&quot; Profile=&quot;domainAndPrivate&quot;/&gt;
&lt;desktop2:Rule Direction=&quot;out&quot; IPProtocol=&quot;GRE&quot; Profile=&quot;private&quot;/&gt;
&lt;/desktop2:FirewallRules&gt;
&lt;/desktop2:Extension&gt;
&lt;/Extensions&gt;

Other noteworthy features

  • Apps can be pre-installed
  • Messaging Application Programming Interface (MAPI) support
  • Windows App Certification Kit now includes test cases for Desktop Bridge apps
  • Use URL flag enables apps to directly open files from a URL instead of downloading a local cached version of the file