Desktop Bridge – Manually converting a desktop application
Published Jan 15 2019 01:56 PM 840 Views
Microsoft
First published on MSDN on Oct 28, 2016

Update: this post has been updated on 11/21/2016 to reflect the official name of Visual Studio 15 Preview announced during Connect() 2016, which is Visual Studio 2107

In the previous post we have seen how, by using the Desktop App Converter tool, it’s possible to convert an installer (like a MSI file) into an AppX, that can be side loaded or published through the Store like a regular Universal Windows Platform application.

In this article, instead, we’ll see the conversion from another point of view: we don’t have an installer, but we have an executable or our own Visual Studio project (like a Windows Forms or a WPF application) and we want to package it as an AppX, so that we can distribute it through the Store. The main reason why we would do this is that, probably, we don’t simply want to publish our installer on the Store as it is, but we want to start changing a bit the code to leverage some of the UWP features, like having a live tile or sending a toast notification.

But let’s take a step back and, before discussing how you can integrate UWP features in a Win32 app (which will be covered in the following posts), let’s see the basics on how to convert an application that doesn’t have an installer to an UWP package.

The manual conversion

We’ve already seen the manual conversion process in the previous post , even if it wasn’t explicated. Do you remember when, after manually changing the content of the Assets folder to replace the standard tiles, we had to use the two tools makeappx.exe and signtool.exe to recreate and sign the .appx package with a valid certificate?

This is exactly what we need to do when we want to convert our application that relies on a single executable file and it doesn’t have an installer process. The only difference is that, in the previous article, we started from a package folder created for us by the Desktop App Converter tool: we already had a folder with an Assets subfolder, a manifest file, etc.

In this case, instead, we need to manually create everything from scratch. So let’s start by creating, on our computer, a folder, where we’re going to recreate the same package structure. The first thing we need to is to take our executable (for example, our .exe file which launches the Windows Forms application) and copy it into the folder. For this demo we’re going to reuse the same Windows Forms application we’ve used in the previous article, which you can find on GitHub at https://github.com/qmatteoq/DesktopBridge/tree/master/1.%20Desktop%20App%20Converter/HelloCente...

You may be wondering why I keep using a Windows Forms app for my demos: there isn’t a specific reason, it’s just to show you that the power of the Desktop Bridge isn’t limited to applications written with more recent technologies like WPF (which has many things in common with the Universal Windows Platform, like relying on XAML to define the UI and C# or VB.NET to define the logic), but it works with any kind of Win32 technologies, even the oldest ones like VB6 or Windows Forms.

If you open the project with Visual Studio and you build it, you’ll get an executable file in the /bin/Debug folder called HelloCentennial.exe . Just take it and copy into the folder you’ve created in the previous step.

The next step is to create a subfolder called Assets , where to place all the images that we need to use as iconography: tiles, start logo, Store logo, etc. The minimum requirement is to have at least two square images: 150x150 and 44x44.

If you want to get a better results and cover all the supported assets and scales, you can refer to the previous post, where we have talked about a Visual Studio extension that is able to generate, from a single image, all the required Assets images.

The last step is to add a manifest file, by manually creating (using whatever editor you prefer, like Notepad, Visual Studio Code or the full Visual Studio version) a file called AppxManifest.xml . We can also copy the one the Desktop App Converter tool created for us in the previous article. No matter how you prefer to proceed, here is how your manifest should look like:

<?xml version="1.0" encoding="utf-8"?>
<Package
xmlns="http://schemas.microsoft.com/appx/manifest/foundation/windows10"
xmlns:uap="http://schemas.microsoft.com/appx/manifest/uap/windows10"
xmlns:rescap="http://schemas.microsoft.com/appx/manifest/foundation/windows10/restrictedcapabilities">
<Identity Name="***YOUR_PACKAGE_NAME_HERE***"
ProcessorArchitecture="x64"
Publisher="CN=***COMPANY_NAME***, O=***ORGANIZATION_NAME***, L=***CITY***, S=***STATE***, C=***COUNTRY***"
Version="***YOUR_PACKAGE_VERSION_HERE***" />
<Properties>
<DisplayName>***YOUR_PACKAGE_DISPLAY_NAME_HERE***</DisplayName>
<PublisherDisplayName>Reserved</PublisherDisplayName>
<Description>No description entered</Description>
<Logo>***YOUR_PACKAGE_RELATIVE_DISPLAY_LOGO_PATH_HERE***</Logo>
</Properties>
<Resources>
<Resource Language="en-us" />
</Resources>
<Dependencies>
<TargetDeviceFamily Name="Windows.Desktop" MinVersion="10.0.14393.0" MaxVersionTested="10.0.14393.0" />
</Dependencies>
<Capabilities>
<rescap:Capability Name="runFullTrust"/>
</Capabilities>
<Applications>
<Application Id="***YOUR_PRAID_HERE***" Executable="***YOUR_PACKAGE_RELATIVE_EXE_PATH_HERE***" EntryPoint="Windows.FullTrustApplication">
<uap:VisualElements
BackgroundColor="#464646"
DisplayName="***YOUR_APP_DISPLAY_NAME_HERE***"
Square150x150Logo="***YOUR_PACKAGE_RELATIVE_PNG_PATH_HERE***"
Square44x44Logo="***YOUR_PACKAGE_RELATIVE_PNG_PATH_HERE***"
Description="***YOUR_APP_DESCRIPTION_HERE***" />
</Application>
</Applications>
</Package>


The items highlighted with asterisks are the ones you need to change to give an identity and a meaningful look & feel to your application, like the name, the package, the logo, the assets to use, the description, etc. However, the most important entry is the one in the Application entry, which is the  path of the Win32 executable you want to package (in our case, it’s the .exe of the Windows Forms app).


Here is how the manifest for our sample application looks like:

<?xml version="1.0" encoding="utf-8"?>
<Package xmlns="http://schemas.microsoft.com/appx/manifest/foundation/windows10"
xmlns:uap="http://schemas.microsoft.com/appx/manifest/uap/windows10"
xmlns:uap3="http://schemas.microsoft.com/appx/manifest/uap/windows10/3" xmlns:rescap="http://schemas.microsoft.com/appx/manifest/foundation/windows10/restrictedcapabilities">
<Identity Name="HelloCentennnial" ProcessorArchitecture="x64" Publisher="CN=mpagani" Version="1.0.0.0" />
<Properties>
<DisplayName>Hello Centennial</DisplayName>
<PublisherDisplayName>Matteo Pagani</PublisherDisplayName>
<Logo>Assets\SampleAppx.150x150.png</Logo>
</Properties>
<Resources>
<Resource Language="en-us" />
</Resources>
<Dependencies>
<TargetDeviceFamily Name="Windows.Desktop" MinVersion="10.0.14393.0" MaxVersionTested="10.0.14393.0" />
</Dependencies>
<Capabilities>
<rescap:Capability Name="runFullTrust" />
</Capabilities>
<Applications>
<Application Id="HelloCentennnial" Executable="HelloCentennnial.exe" EntryPoint="Windows.FullTrustApplication">
<uap:VisualElements DisplayName="Hello Centennnial " Description="Hello Centennnial " BackgroundColor="#777777"
Square150x150Logo="Assets\SampleAppx.150x150.png" Square44x44Logo="Assets\SampleAppx.44x44.png" />
</Application>
</Applications>
</Package>


At the end, here is how your folder should look like:



For your convenience, if you don’t want to recreate everything manually just for the sake of testing, you can download a full copy of the package structure from GitHub: https://github.com/qmatteoq/DesktopBridge/tree/master/2.%20Manual/PackageLayout


A first important thing to highlight is that, with this architecture in place, you’ll be able to test your desktop app running as converted without necessarily having to create an AppX package from it and install it. In fact, it’s enough to open a Powershell window in this folder and launch the following command:

Add-AppxPackage -Register ".\AppxManifest.xml"

The application will be installed like if it would have been downloaded from the Store or directly from the AppX and you’ll find it in the application list of your Start menu. This is an easy way to test changes in the package: just change the files (like an asset or an updated executable), then register it again and you’re all set to test the new version.


Now, instead, let’s see how we can turn this folder into a real AppX package thanks to the exact same manual approach we’ve seen in the previous article, when we have manually replaced the assets and recreated the package.


First, we’re going to open a Visual Studio Command Prompt and leverage the makeappx.exe tool to create the .appx file:

makeappx pack -d "C:\Centennial\PackageLayout" -p "C:\Centennial\Output\HelloCentennial.appx"

You should already know the meaning of the various parameter, thanks to the previous post : -d is the path to the package folder, while -p is the path and name of the AppX file we want to create.


At the end of the process, we’ll get a file called HelloCentennial.appx which, however, we won’t be able to install because it isn’t properly signed. Again, we need to use another tool we’ve covered in the previous article, which is signtool.exe . You can choose to leverage the auto generated certificates from the Desktop App Converter or to create your own, by following the steps described in this article: https://msdn.microsoft.com/en-us/windows/uwp/porting/desktop-to-uwp-signing


No matter which is your choice, in the end you’re going to launch a command similar to the following one:

signtool.exe sign /a /v /fd SHA256 /f "auto-generated.pfx" /p "123456" "HelloCentenniall.appx"

Again, the important parameters are:



  • /f , which is the path to the PFX file to use for the signature
  • /p , which is the password used to protect the PFX file (if needed)
  • the path and name of the .appx file to sign

We’re done! Now we have an AppX package that we can install on our machine or, eventually, publish on the Store that will launch our Windows Forms app, which we have included as executable inside the package.


Important! In the manifest file, we just need to specify the entry point of the Win32 application (in our case, the file called HelloCentennial.exe ), but in the package folder we need to remember to add also all the DLLs which the app depends from (no matter if they have been created by you or if they’re third party libraries), otherwise we’ll get exceptions at runtime.


For example, let’s say that we want to add a new feature in the Windows Forms app: we want to serialize some data using the JSON format and store it into a text file saved on the desktop. To simplify our job, we add the third-party library JSON.NET to the Windows Forms application using NuGet and, in the user interface, we add a button that invokes the following method:

private void OnSerializeData(object sender, EventArgs e)
{
Person person = new Person();
person.Name = "Matteo";
person.Surname = "Pagani";

var json = JsonConvert.SerializeObject(person);
string userPath = Environment.GetFolderPath(Environment.SpecialFolder.DesktopDirectory);
string fileName = $"{userPath}\\person.txt";
File.WriteAllText(fileName, json);
}


If we build again the project in Visual Studio and we copy inside the PackageLayout folder just the updated HelloCentennial.exe file, but we forget to copy also the Newtonsoft.Json.dll one (which is the JSON.NET library installed through NuGet), we’ll get an unhandled exception when we’ll try to call this method in the UWP app, which will simply crash.


This example shows you some of the limitations of the manual approach:



  1. Every time we make some changes to the Windows Forms application, we need to remember to copy all the updated files in the package folder before creating a new version of the AppX file or manually registering it using Powershell. In this sample app, the operation is quite easy, since it’s made just by an executable and a third-party library. We can’t say the same if we’re working on a more complex app, which may contain dozens of class libraries that can be modified and updated every time we rebuild the project.
  2. When we have added the new method to serialize the data, we’ve created a dependency from the JSON.NET library, which we need to remember to include in the package folder. If we forget to do it, it can be hard to debug and identify the problem, because when we launch the Windows Forms app everything works as expected. However, as soon as we launch the converted AppX package, we would just notice that the app crashes but, without adding proper logging, we won’t be able to immediately identify the cause.
  3. In the end, there’s one last caveat: every time we need to deploy an updated version of the package for testing, we need to repeat the package creation and signing process or the Powershell script.

Is there a way to improve the overall conversion experience?


Introducing Visual Studio 2017


Visual Studio 2017 (previously known as Visual Studio 15) is the name of the next version of Visual Studio, which will ship in the near future and, at the time of writing, has reached the RC milestone. Visual Studio 2017 adds a lot of new features and improvements and some of them will be particularly appreciated by Universal Windows Platform developers (like the XAML Edit and continue feature, which allows to change the content of a XAML page while the app is running and to see the changes live in real time). Additionally, Visual Studio 2017 comes with a new installer, which will allow you to install only the feature you need for your environment: this way, a basic installation can take just a few minutes to be completed, which is a huge improvement compared to the past. Then, dynamically, you can start adding new modules as you need, based on your requirements.


Visual Studio 2017 comes with an extension which is specific for the Desktop Bridge, which makes the conversion and debugging experience much easier. In this section, we’re going to achieve the same goal of the previous exercise (taking the HelloCentennial.exe application and converting it into a UWP app), but using Visual Studio 2017 and the Desktop Bridge extension.


The first step is to install Visual Studio 2017 RC: it has a go-live license but it’s still in preview so, if you don’t feel confident, you can install it side by side with all the other Visual Studio installationsEventually, if you prefer not to mix production environment and testing environments, you can choose to install it on a virtual machine hosted on your own PC or on Azure. You can download the preview from https://www.visualstudio.com/vs/visual-studio-2017-rc/



The next step is to download and install the extension dedicated to the Desktop Bridge from the Visual Studio gallery: http://go.microsoft.com/fwlink/?LinkId=797871


After we have installed everything, let’s start by creating a new Win32 app. For our demo, we’re going to reuse the HelloConverter project we’ve previously converted, which source is available on GitHub: https://github.com/qmatteoq/DesktopBridge/tree/master/3.%20Convert


As you can see, it’s the same Windows Forms app we’ve used in the previous articles: it’s made by a single form with two buttons, which creates some text files on the user’s desktop.



If we take a look at Solution Explorer, however, we can notice that, other than the Windows Forms project, there’s also another project, called Convert.DesktopToUWP . This project has been created thanks to the new template added by the extension. To add it, just right click on the solution in Visual Studio and choose Add -> New Project . You’ll find the template under Other Project Types -> Setup and deployment and it’s called Desktop to UWP Packaging Project .



By default, the new project will look like this:



As you can see, it contains a single file, called AppXPackageFileList.xml . This is the file that does all the deployment work for us: it describes which are the files of the original Win32 project that need to be embedded into the UWP package. Here is how the default file looks like:

<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<!--
<PropertyGroup>
<MyProjectOutputPath>C:\MyProject\MyProject\bin</MyProjectOutputPath>
</PropertyGroup>
<ItemGroup>
<LayoutFile Include="$(MyProjectOutputPath)\x86\Debug\MyProject.exe">
<PackagePath>$(PackageLayout)\MyProject.exe</PackagePath>
</LayoutFile>
</ItemGroup>
-->
</Project>


The content of the file is commented, since you need to change it with the real info about your app, but it gives you a glimpse of the information needed to get it working:



  • The MyProjectOutputPath entry contains the path of the folder where Visual Studio deploys the files that need to be included into the package. Typically, it’s the output of the build operation of the Win32 app, which is stored inside the bin folder of the project .
  • The ItemGroup section contains one or more LayoutFile entry, one for each file that needs to be packaged into the AppX. Typically, you’re going to have one entry for each .exe and each .dll file needed by the Win32 app to properly run.

Before moving on, it’s important to do a step back and highlight an important information: this extension doesn’t remove the requirement of having to manually create a package folder with the assets and the manifest file, like we did with the manual approach. You’ll still have to do this operation: the difference is that, this time, instead of creating the package folder in a random position on your computer, you’re going to include it into the new deployment project we’ve just created, as you can see in the following image:



The PackageLayout folder is exactly the same folder, with the same Assets subfolder and the same AppxManifest.xml file, we’ve created at the beginning of this article. The only difference is that, this time, we don’t have any more to manually add the HelloCentennial.exe and the Newtonsoft.Json.dll files, but the project will take care of it for us every time we build it.


Once you’ve added the PackageLayout folder to your deployment project, you’ll need to set its path in the Package Layout field in the Start section of the project’s properties, which you can find by right clicking on the project and choosing Properties . As you can see, the project supports relative paths, so it’s enough to specify the name of the folder (in this case, PackageLayout ).



After you’ve done this operation, you should be able to choose from the Start Up Tile dropdown the name of the Win32 application that will be launched by the UWP package (in this case, it’s Convert ).


The last step is to configure the AppXPackageFileList.xml to configure which files from the Windows Forms project are required by the UWP app to run properly:

<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<MyProjectOutputPath>$(PackageLayout)\..\..\Convert\bin</MyProjectOutputPath>
</PropertyGroup>
<ItemGroup>
<LayoutFile Include="$(MyProjectOutputPath)\Debug\Convert.exe">
<PackagePath>$(PackageLayout)\Convert.exe</PackagePath>
</LayoutFile>
<LayoutFile Include="$(MyProjectOutputPath)\Debug\Newtonsoft.Json.dll">
<PackagePath>$(PackageLayout)\Newtonsoft.Json.dll</PackagePath>
</LayoutFile>
</ItemGroup>
</Project>


As you can see, in the MyProjectOuputPath entry we’re leveraging the $(PackageLayout) keyword, which is automatically mapped with the path we’ve specified in the project’s property as Package Layout . This way, instead of specifying an absolute path, we can use a relative one to point to the folder where Visual Studio deploys the app executables every time we build the project (the bin one of the Windows Forms project).


Then, by leveraging another keyword ($MyProjectOutputPath) (which, as you can imagine, is a reference to the entry we’ve just declared above), we create a LayoutFile entry for each file stored in the bin folder that we need to include in the UWP package: in our case, we need to include the executable ( HelloCentennial.exe ) and the JSON.NET DLL ( Newtonsoft.Json.dll ).


Now, if we build the deployment project and deploy it, Visual Studio will take care of automatically copying the required files from the desktop app. We can notice this by simply opening, in File Explorer, the PackageLayout folder: other than the Assets folder and the manifest file we’ve previously created, we will find also the Windows Forms executable and the JSON.NET library.



If we set the deployment project as the startup one, we should immediately see another one of the benefits of using VS15 with this extension: we’ll be able to simply press F5 and deploy and launch the desktop app inside the UWP container, without having first to create the AppX and sign it with the command line tools.


Another additional benefit is that now we have a true debugging experience: despite we have launched the UWP packaged version of the app, we can add breakpoints in the Windows Forms project and hit them, like if we were regularly debugging the standard Win32 app.


Another advantage is that we can easily identify errors that don’t happen in the Windows Forms app, but only in the UWP packaged version. Do you remember the crash scenario we mentioned in the beginning, in case we forget to include in the package the JSON.NET DLL? Thanks to VS15 it’s easy to identify and solve it because, in this case, instead of an unexpected crash, we get a full debugging experience, with all the details about the exception:



At the moment of writing, however, VS15 still doesn’t include an automatic process to convert the deployment project into an AppX package: as such, once you have finished testing and debugging and you want to prepare the .appx file for distribution, you still have to go back to the manual approach and use the makeappx.exe and signtool.exe tools that we have previously described on the PackageLayout folder.


Wrapping up


In this article, we’ve learned how to leverage another approach provided by the Desktop Bridge: instead of converting an installer, we have converted an executable, in this case a Windows Forms project that we own. To achieve this goal, we have created a folder where we have included all the files that we need to include in the AppX package: assets, manifest and the Win32 application.


However, we have discovered that there are two ways to accomplish this task:



  1. A manual approach, which requires to manually copy into the package folder all the executables and DLLs every time we change the source code of our Win32 app.
  2. An automatic approach, which is based on a special extension available for Visual Studio 2017. Thanks to this extension, every time we apply a change to the Win32 app, the required files are automatically copied in the UWP package. Additionally, we get a full debugging and deployment experience, without having to create and sign an AppX package every time we need to do some testing.

As usual, you can find all the samples on my GitHub repository: https://github.com/qmatteoq/DesktopBridge . Specifically, the projects used for this article are:



In the next article, we’re going to expand this sample app and see how we can start integrating UWP APIs and features.


Happy coding!

Co-Authors
Version history
Last update:
‎Nov 22 2022 12:21 PM
Updated by: