UWP with Desktop Extension – Part 2

desktop_blue

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

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

TL;DR;

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

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

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

Multiple Desktop Processes

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

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

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

screenshot3

In-package vs out-of-package

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

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

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

screenshot6

Background Processes

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

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

Passing in Launch Parameters

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

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

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

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

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

UWP side (MainPage.cs):

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

 await FullTrustProcessLauncher.LaunchFullTrustProcessForCurrentAppAsync("Parameters");
}

Win32 side (Program.cs)

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

screenshot7

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

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

Advertisements

8 thoughts on “UWP with Desktop Extension – Part 2

  1. Thanks for the posts.

    I wonder if it is also possible to force started full trust application into “as administrator” mode? Both UAC prompt and launching the app as administrator at all times (as opposed to selective) would be acceptable.

    I am afraid this is not possible? I found this SO post https://stackoverflow.com/a/50829593/868014 where you seem to write exactly this, and maybe RS5 will bring this option.

    Like

    1. Hi Roman,

      Yes this is coming in RS5 (Fall 2018 update). We will enable both scenarios (requesting elevation at launch as well as launching a process as elevated on demand). You should be able to start playing with this on the latest Windows Insider OS build, with the latest insider SDK build (17692 or later). To enable this, add the “allowElevation” capability to your appxmanifest.

      Thanks,
      Stefan

      Liked by 1 person

      1. Hi Stefan,

        Regarding the “allowElevation” capability you mention above, would you have a working example?

        i have read the document at https://docs.microsoft.com/en-us/windows/uwp/packaging/app-capability-declarations and played around but couldn’t get it to work. In my case, I have a UWP and WPF app, which is an set to a desktop extension and launched from the UWP by following your example. I wish the WPF app is running in elevated mode but it is not.

        Regards

        John

        Like

  2. Hi Stefan,

    Thank you for the quick reply and the instructions on how to get an elevated app running.

    Unfortunately, I don’t have a Windows 10 with build 17744 so I wouldn’t be able to exercise for now. I shall try in the future.

    Regards

    John

    Like

  3. Hi

    First of all thanks for your valuable examples. I have a related problem I would like your opinion about it. Hope you find it interesting and has the time to give it a comment. It already costed me a week of work without successfully result.:-(

    Very simplified I have an old WPF LOB application, and then a new UWP one under development. Both runs on the same machine on Windows 10 LTSB version (Anniversary Update 143939). While the UWP version is under development I want to be able to switch easily between the two applications. I have added a switch button in both applications.

    It was simple to get the WPF to launch the UWP versions using protocol activation. The other way is the one giving me gray hair. Using desktop extension is there any way to easily let the UWP bring an already running instance of the WPF application into front.

    I should say that my Windows 10 runs in tablet mode and it seems like that it prevents the wpf application from being restored/maximized. The wpf application will remain stucked in the taskbar (= blinking in the taskbar).

    So to summarize my question. “Can my UWP app send an already running WPF application into front running on Windows 10 LTSB (14393) in tablet mode?”.

    Like

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s