Running a Windows UI (Project Reunion) App as Partial Trust (Windows App Container)

I’ve covered this a couple of times already but it’s already possible to run a Windows UI (aka WinUI / Project Reunion) app as “partial trust”. This is roughly equivalent to the security context of a UWP application. However, there are some difference, which I’m assuming Microsoft will have to bridge if they’re going to … Continue reading “Running a Windows UI (Project Reunion) App as Partial Trust (Windows App Container)”

I’ve covered this a couple of times already but it’s already possible to run a Windows UI (aka WinUI / Project Reunion) app as “partial trust”. This is roughly equivalent to the security context of a UWP application. However, there are some difference, which I’m assuming Microsoft will have to bridge if they’re going to bring WinUI apps to other devices, such as Xbox, Hololens and the now defunct Windows10X. In this post we’re going to look at some of the limitations of partial trust and discuss what this means for the future of Windows app development.

Before we kick off, if you’re interested in a more detailed coverage on my thoughts regarding the future of Windows app development, and how it aligns with cross platform technologies such as Uno, check out my recent article on InfoQ: The Future of Windows (and Other Platforms) Development.

Run in App Container

When you first create a WinUI project using the project templates provided by Microsoft you’re currently given two projects: the application project and an associated packaging project. Microsoft has already indicated that the long term goal is to remove the need for the packaging project and to support unpackaged applications. However, these changes won’t really impact the underlying decisions that a developer needs to make about the security model for the application.

The linkage between the packaging project and the application project is via the Dependencies list inside the packaging project (if you ever have to manually add a packaging project to an existing application you simply create the project and add a reference to the existing application). This is shown in the following image where the ImageLoadingSample application appears under the Applications node under Dependencies of the Package project.

What’s not immediately obvious is that there are properties associated with this linkage, which are visible in the Properties window when the application dependency has focus. The following image shows the properties that relate to the ImageLoadingSample application.

In this case you’ll notice that I’ve already adjusted the Trust Level from the default level, which is Full Trust, to Partial Trust. You can think of this setting as controlling the security context that the application is going to run in. By switching from Full to Partial Trust, we’re effectively forcing the application to be run in the Windows Application Container (more on appcontainer isolation).

We also need to remove the “runFullTrust” capability from the package.manifest file. It’s important to remove this capability otherwise users downloading the app from the Store will see the run as full trust requirement. Lastly, we need to make sure we have a PhoneIdentity element in the package.manifest file – simply add a new PhoneIdentity element immediately after the existing Identity element; set the PhoneProductId attribute to be the same as the Name property of the Identity (assuming it’s a guid, if not, create a new guid and use that as the PhoneProductId) and then set the PhonePublisherId to an all zeros guid.

Now we’re ready with our application to run as partial trust. If you run the application, you can verify that it’s running as partial trust using Process Explorer and inspecting the Integrity flag value – it should be Low Mandatory Level.

Now that we’re running as partial trust, i.e. in the app container, what does this mean for our application. Well initially, it probably doesn’t seem to have much effect. However, you’ll most likely notice that there are some things that don’t quite behave as normal.

Image Loading (InternetClient Capability)

One thing that tripped me up recently was that I was working on an app and I’d set it to run as partial trust. I went about building out the application and everything was going smoothly until I ran the application and realised that the images weren’t loading (they were images specified using a url, eg. https://docs.microsoft.com/en-us/windows/apps/images/logo-winui.png) What was concerning was that the application didn’t raise any sort of error. The ImageFailed event on the Image control didn’t get raised. and there were no internal exceptions raised in either managed or native code that the debugger would break on.

I immediately thought that something had been broken in the 0.8 preview of WinUI. It was only later that it came to me that it must be because my application is running with low integrity, meaning that I need to request capabilities for even basic things like internet access.

Sure enough, by adding the internetClient capability (eg <Capability Name="internetClient"/> ) to the package.manifest file, the images started appearing. Note, that after making changes to the package.manifest file, make sure you uninstall the application and do a rebuild of the packaging application to make sure the latest changes are applied to your application.

File Picker

One of the current cludges that’s required for WinUI is that if you want to use the file picker api, you need to grab a reference to the hwnd of the application window. For example, the following code is almost identical to what you’d write in a UWP application, except for the hacky code required to retrieve the Window’s hwnd and the subsequent calls to initialize the picker with the hwnd value (example taken from this github issue). Note that to get this to work, you need to add “using WinRT;” to the top of the file to make sure the As extension is available (instead of the static As method that is available on the Window class).

private async void PickFile(object sender, RoutedEventArgs e)
{
    var picker = new Windows.Storage.Pickers.FileOpenPicker();

    //Get the Window's HWND
    var hwnd = this.As<IWindowNative>().WindowHandle;

    //Make folder Picker work in Win32
    var initializeWithWindow = picker.As<IInitializeWithWindow>();
    initializeWithWindow.Initialize(hwnd);

    picker.ViewMode = Windows.Storage.Pickers.PickerViewMode.Thumbnail;
    picker.SuggestedStartLocation = Windows.Storage.Pickers.PickerLocationId.PicturesLibrary;
    picker.FileTypeFilter.Add(".jpg");
    picker.FileTypeFilter.Add(".jpeg");
    picker.FileTypeFilter.Add(".png");

    Windows.Storage.StorageFile file = await picker.PickSingleFileAsync();
    if (file != null)
    {
        // Application now has read/write access to the picked file
        FilePickerResult.Text = "Picked photo: " + file.Name;
    }
    else
    {
        FilePickerResult.Text = "Operation cancelled.";
    }
}

Despite this being quite hacky, and hopefully something the team will clear up, this does at least work. More importantly, it displays the traditional file picker dialog that we’re all used to from Windows, rather than the crippled version that UWP apps need to suffer.

Unfortunately, due to the need to retrieve the hwnd and associate the hwnd with the picker, it is not possible to use this file picker when the application is running as partial trust. When we run the application in partial trust, an UnauthorizedAccessException is raised.

Removing the failing call to Initialize isn’t an option either – this results in a COMException that indicates an “Invalid window handle (0x80070578)”.

Partial v Full Trust

As you can see from these examples it is possible to run applications in partial trust, which will result in them running in the app container with permissions limited based on the requested capabilities. The second example illustrates that whilst you can run your application in partial trust, not everything will necessarily work (even if you do request the correct capabilities).

You’d be right in wondering why Microsoft have shipped WinUI/Project Reunion when there are clearly scenarios where some of the core features don’t work. It’s reasons like this that is entirely why Project Reunion is still not v1.0. However, if you look at the priorities, it doesn’t look like these issues will necessarily be fixed in the v1.0 timeline. Currently, running in partial trust isn’t discussed much and there’s almost no documentation on it. Further more, the team are being clear that there are scenarios where things won’t work correctly when running as partial trust (for example comments by Peter Torr in a discussion relating to app containers)):

There are some niche scenarios where it can work, but by and large it won’t work for most scenarios…

Peter Torr, Microsoft

At this stage I would encourage developers to work with the latest stable (or preview) bits of Project Reunion in order to develop and test applications. If your application works under partial trust, then that’d be the preference but at this stage, if basic functionality like file picking doesn’t work, I’d be surprised if anything other than a trial application could be built without running into issues when running as partial trust.

Leave a Reply

Your email address will not be published. Required fields are marked *