Modernize Desktop Apps On Windows 10 With NET Core 3
Modernize Desktop Apps On Windows 10 With NET Core 3
All rights reserved. No part of the contents of this book may be reproduced in any form or by any
means without the written permission of the publisher.
This book is available for free in the form of an electronic book (eBook) available through multiple
channels at Microsoft such as http://dot.net/architecture
This book is provided “as-is” and expresses the author’s views and opinions. The views, opinions and
information expressed in this book, including URL and other Internet website references, may change
without notice.
Some examples depicted herein are provided for illustration only and are fictitious. No real association
or connection is intended or should be inferred.
Microsoft and the trademarks listed at http://www.microsoft.com on the “Trademarks” webpage are
trademarks of the Microsoft group of companies. All other marks are property of their respective
owners.
PREVIEW EDITION
This book is a preview edition and is currently under construction. Submit your
feedback at https://aka.ms/ebookfeedback.
Co-Authors:
Miguel Ramos, Sr. PM, Windows Developer Platform team, Nish Anil, Sr. PM, .NET team, Microsoft
Microsoft
Beth Massi, Sr. Product Marketing Manager, Microsoft
Adam Braden, Principal PM, Windows Developer Platform
team, Microsoft Marta Fuentes Lara, Kabel
Maira Wenzel, Sr. Content Developer, Microsoft Raúl Fernández de Córdoba, Kabel
Andy De Gorge, Sr. Content Developer, Microsoft Antonio Manuel Fernández Cantos, Kabel
Ricardo Minguez Pablos, Sr. PM, Azure IoT team, Microsoft Scott Hunter, Partner Director PM, .NET team, Microsoft
Contents
Why Modern Desktop Applications? ............................................................................................................................... 1
Introduction........................................................................................................................................................................... 1
Desktop applications nowadays.................................................................................................................................... 2
A tale of two platforms ..................................................................................................................................................... 5
Paths to modernization .................................................................................................................................................... 7
What this guide does not cover .................................................................................................................................... 8
Who should use this guide ............................................................................................................................................. 8
How to use this guide ....................................................................................................................................................... 8
Sample apps .......................................................................................................................................................................... 9
Send us your feedback...................................................................................................................................................... 9
What’s new with .NET Core 3.0 for Desktop? ............................................................................................................ 10
From .NET Framework to .NET Core. The motivation behind .NET Core ................................................... 10
Introduction to .NET Core ............................................................................................................................................. 11
.NET Framework vs .NET Core ..................................................................................................................................... 13
.NET Standard versus PCL ............................................................................................................................................. 15
.NET Core 3.0 new Desktop features ........................................................................................................................ 15
Benefits of Open Source ............................................................................................................................................... 16
Migrating Modern Desktop Applications ................................................................................................................... 18
Configuration files ........................................................................................................................................................... 18
Accessing Databases....................................................................................................................................................... 20
Consuming services ............................................................................................................................................................ 21
Consuming a COM Object ........................................................................................................................................... 22
More things to consider ................................................................................................................................................ 22
Windows 10 Migration ....................................................................................................................................................... 24
Introduction........................................................................................................................................................................ 24
WinRT APIs.......................................................................................................................................................................... 24
How to add WinRT APIs to your desktop project ............................................................................................... 27
XAML Islands...................................................................................................................................................................... 33
Migrating an example desktop application to .NET Core 3.0 ............................................................................. 38
iii Contents
Introduction........................................................................................................................................................................ 38
Migration Process Overview ........................................................................................................................................ 38
Migrating a Windows Forms application................................................................................................................ 42
Migrating a WPF Application ...................................................................................................................................... 48
Deploying Modern Desktop Applications .................................................................................................................. 50
Introduction........................................................................................................................................................................ 50
The modern application lifecycle ............................................................................................................................... 50
MSIX: The next generation of deployment ............................................................................................................ 51
How to create a MSIX package from an existing Win32 desktop application ........................................ 54
Auto Updates in MSIX .................................................................................................................................................... 60
CHAPTER 1
Why Modern Desktop Applications?
Introduction
A story of one company
Back in early 2000’s one multinational company started developing a distributed desktop solution to
exchange information between different branches of the company and execute optimized operations
on centralized units. They have chosen a brand-new framework called Windows Forms for their
application development. Over years the project evolved into a mature well tested and time proven
application with hundreds of thousands of lines of code. Time passed and .NET Framework 2.0 is no
longer the hot new technology. The developers who are working on this application are facing a
dilemma. They would like to use the latest stack of technologies in their development and have their
application look and “feel” modern. At the same time, they don’t want to throw away the great
product they have built over 15 years and rewrite the entire application from scratch.
Your story
You might find yourself in the same boat, where you have mature Windows Forms (also known as
WinForms) or WPF (Windows Presentation Foundation) applications that have proved their reliability
over the years. You probably want to keep using these applications for many more years. At the same
time, since those applications were written some time ago, they might be missing capabilities like
modern look, performance, integration with new devices and platform features and so on, which gives
them a feel of “old tech”. There is another problem that might concern you as a developer. While
working on the older .NET Framework versions and maintaining applications that were written a while
ago, you might feel like you aren’t learning new technologies and missing on building modern
technical skills. If that is your story – this book is for you!
Microsoft approach to modernizing existing applications is to give you the flexibility to create your
own customized path. All the modernization strategies described in this book are mostly independent.
You can choose ones that are relevant for your application and skip others that aren’t important for
you. In other words, you will be able to mix and match the strategies to best address your application
needs.
Then, Internet technologies started shocking the development world and winning over more and
more engineers with advantages like easy deployment and simplified distribution processes. The fact
that once Web application was deployed to production all users got automatic updates made a huge
impact on the software agility.
However, the Internet infrastructure, underlying protocols and standards like HTTP and HTML were
not design for building complex applications. In fact, the major development effort back then was
aiming just one goal: to give Web applications same capabilities that desktop applications have, such
as fast data input, state management and so on.
Even though Web and Mobile applications have grown at an incredible pace, for certain tasks desktop
applications still hold the number one place in terms of efficiency and performance. That explains why
there are millions of developers who are building their projects with WPF and WinForms and the
amount of those applications is constantly growing.
Here are some reasons for choosing desktop applications in your development:
So, as you can see, developing for desktop is great for many reasons. The technology is mature and
time tested, the development cycle is fast, the debugging is powerful and arguably, desktop apps
have less complexity and easier to get started with.
Microsoft offered a variety of UI desktop technologies through the years from Win32 introduced in
1995 and to UWP released in 2016.
You can develop in any of them using C# and VB.NET, but let’s take a closer look.
Windows Forms
First released in 2002, Windows Forms is a managed framework and is the oldest, most used, desktop
technology built on the Windows GDI engine. It offers a very smooth drag-and-drop experience for
developing user interfaces in Visual Studio. At the same time, Windows Forms relies on the Visual
Studio Designer as the main way you develop your UI, so creating visual components from code is not
trivial.
• Mature technology.
• Designer is available, but developers usually prefer to create the design from code using
declarative XAML.
• The learning curve is steeper than Windows Forms.
• Supported on any Windows version.
• Supported on .NET Core 3.0.
UWP
The Universal Windows Platforms is not only a presentation framework like WPF and Windows Forms,
but it is also a platform itself. This platform has its own API set (the Windows Runtime API), a new
deployment system (MSIX), a modern application lifecycle model (for low battery consumption), a new
Resource Management System (based on PRI files), among other things. The platform was created to
support all kind of input systems (like ink, touch, gamepad, mouse, keyboard, gaze, etc.) in all form-
factors with performance and low battery consumption in mind. For these reasons the Shell of the
Windows 10 OS uses parts of the UWP platform.
• Applications are executed in app containers. App containers are a sandbox mechanism which
control what resources an UWP app can access or not.
• Supported only on Windows 10.
• Apps can be deployed through Microsoft Store for easier deployment besides sideload.
• Designed as part to the Windows Runtime API.
• Contains an extensive set of built-in rich controls and additional controls in the Microsoft UI
Library NuGet packages (WinUI library) updated every few months.
We can describe the differences between the two concepts in the following table:
Security Contained execution & Great User & Admin level of security.
Fundamentals.
You have native access to the Registry
Design from the ground up to respect and Hard Drive folders.
user privacy, manage battery life and
focus to keep the device safe.
Deployment Installation and updates are managed MSI, Custom installers & Updates.
by the platform.
Traditionally a source of headaches
for developers and IT managers.
Distribution Trusted Distribution & Signed Web, SCCM & Custom distribution.
Packages.
No control over what is installed,
Distribution is performed from a affects the whole machine.
trusted source and never from the
Web.
As a part of the commitment to provide developers with the best tools to build applications, Microsoft
has performed a great effort to bring these concepts, or we can even say platforms, closer together to
empower developers with the best of both worlds. To do that, Microsoft has performed a bidirectional
effort between the two platforms.
1. Move Desktop Application scenarios into Modern Application platform. The traditional
desktop development is still very popular because it addresses certain scenarios really well. It
2. Move Modern Application features into Desktop Applications. For existing desktop apps that
need a way to leverage modern capabilities without rewriting from scratch, features from the
Modern Application platform are pushed into the Desktop Application.
In this book we will focus on the second part and show how you can modernize your existing desktop
applications.
Paths to modernization
The structure of this guide reflects three different axes to accomplish modernization: Modern
Features, Deployment and Installation.
Modern Features
Say you have a working Windows Forms application that a sales representative of your company uses
to fill in a customer order. A new requirement comes in to enable the customer to sign-in the order
using a tablet pen. Inking is native in today´s operating systems and technologies but was not
available when the app was developed.
This path will show you how you can leverage modern desktop features into your existing desktop
development.
Now, with the launch of .NET Core 3.0, you can leverage a radically new approach of deploying
multiple versions of .NET Core side by side and specifying which version of .NET Core each application
should target. This way, you can use newest features in one application while being confident you
aren’t going to break any other applications.
Installation
Desktop applications always rely on some sort of installation process before the user can start using
them. This brought into the game a set of technologies, from MSI and ClickOnce to custom installers
or even XCOPY deployment. Any of these methods deals with delicate problems because applications
need a way to access shared resources on the machine. Sometimes installation needs to access the
Registry to insert or update new Key Values, sometimes to update shared DLLs referenced by the
main application. This causes a continuous headache for users, creating this perception that once you
install some application, your computer will never be the same, even if you uninstall it afterwards.
In this book, we will introduce a new way of installing applications with MSIX that solves the problem
described above. You will learn how you can easy set up a packaging, installation and updates for
your application.
This guide is not about developing modern applications with .NET Core or implementing desktop
scenarios into the Modern Application Platform. If focus on how you can leverage your investments
on desktop applications while you keep them updated with some of the latest technologies for
desktop development.
You also might find this guide useful if you are a technical decision maker, such as an enterprise
architect or a development lead/director who just wants an overview of the benefits that you can get
by updating existing Desktop Apps.
Along the different chapters, sample implementation code snippets and screenshot are provided, with
chapter 5 devoted to a showcase a complete migration process for sample applications.
Sample apps
To highlight the necessary steps to perform a modernization we will be using a sample application
called eShopModernizing. This application has two flavors, Windows Forms and WPF and we will show
a step by step process on how to perform the modernization on both of them to .NET Core.
Also, on the GitHub repo for this book, you will find the results of the process, which you can consult
with if you decide to follow the step-by-step tutorial.
If you are targeting only one of these platforms, you can use this model. However, in many cases you
might need more than one target platform in the same solution. For example, your application may
have a desktop admin part, a customer-facing web site that shares the backend logic running on a
server, and even a mobile client. In this case, you need a unified coding experience that can span all
this .NET verticals.
By the time Windows 8 was released, the concept of the Portable Class Libraries (PCL) was born.
Originally, the .NET Framework was designed around the assumption that it is always deployed as a
single unit, so factoring was not a concern. To face the problem of code sharing between verticals, the
driving force was on how to refactor the framework. The idea of contracts is to provide a well factored
API surface area. Contracts are simply assemblies that you compile against and are design with proper
factoring in mind taking care of the dependencies between them.
This leads to a reasoning about the API differences between verticals at the assembly level, as
opposed to the individual API level that we had before. This aspect enabled a class library experience
that can target multiple verticals, also known as portable class libraries.
With PCL the experience of development is unified across verticals base on the API shape and the
most pressing need to create libraries running on different verticals is addressed. But there is still a
A better approach is to unify the implementations across verticals by providing a well factored
implementation instead of a well factored view. It is a lot simpler to ask each team owning a specific
component to think about how their APIs work across all verticals than trying to retroactively provide
a consistent API stack on top. This is where .NET Standard comes in, see details on next section.
Another big challenge has to do with how the .NET Framework is deployed. The .NET Framework is a
machine-wide framework. Any changes made to it affect all applications taking a dependency on it.
Although this has many advantages like reducing disk space and centralized access to services, it
presents some pitfalls.
To start with, it is difficult for application developers to take a dependency on a recently released
framework. You have either to take a dependency on the latest OS or provide an application installer
that will install the .NET Framework along with the application. If you are a web developer, you might
not even have this option as the IT department establishes the server supported version.
Even if you are willing to go through the trouble of providing an installer in order to chain in the .NET
Framework setup, you may find that upgrading the .NET Framework can break other applications.
Despite the efforts to provide backward compatible versions of the framework, there are compatible
changes that can break applications. For example, adding an interface to an existing type that can
change how this type is serialized and cause breaking problems depending on the existing code.
Because NET Framework installed base is huge, fighting against these breaking scenarios slows down
the pace of innovations inside the .NET Framework.
To solve all these issues Microsoft has developed .NET Core to approach the evolution of the .NET
Platform.
This framework gives applications many benefits in terms of efficiency and performance, simplifying
the packaging and deployment in the different supported platforms.
In .NET Core 3.0, there is planned support for developing the following application types:
The goal for this framework is quite impressive: to target every type of .NET development present and
future including Desktop, Web, Cloud, Mobile, Gaming, IoT and AI. Microsoft plans to complete this
vision with .NET 5 at the end of 2020. Note that the “Core” name was removed to reinforce its
uniqueness in the .NET World.
XAML Islands
XAML Islands is a set of components for developers to use the new Windows 10 controls (UWP XAML
controls) in their current WPF, Windows Forms, and native Win32 apps (like MFC). You can have your
“islands” of UWP XAML controls wherever you want inside your Win32 apps.
To facilitate to create XAML Islands for Windows Forms and WPF developers, the Windows
Community Toolkit introduces a set of .NET wrappers in several NuGet packages. Those wrappers are
the Wrapped Controls and Hosting Controls:
Performance
Since its inception, targeting the Web and Cloud workloads, .NET Core has had performance plugged
into its DNA. Server-side code must be performant enough to fulfill high concurrency scenarios and
.NET Core scores today as the best performance web platform in the market.
You can now take advantage of these performance improvements when you use it to build your next
generation of desktop applications.
Configuration files
Configuration files offer the possibility to store sets of properties that are read at runtime, affecting
the behavior of the application, like where to locate a database or how many times to execute a loop.
This comes in handy when for example the same app code runs on a development environment with a
certain set of configuration values and in production with a different one.
<configuration>
<system.diagnostics>
<switches>
<add name="General" value="4" />
</switches>
<trace autoflush="true" indentsize="2">
<listeners>
<add name="myListener" type="System.Diagnostics.TextWriterTraceListener, System,
Version=1.0.3300.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
initializeData="MyListener.log" traceOutputOptions="ProcessId, LogicalOperationStack, Timestamp,
ThreadId, Callstack, DateTime" />
</listeners>
</trace>
</system.diagnostics>
</configuration>
If you use this configuration with .NET Core, you will get an exception:
This is because the system.diagnostics section, and the assembly responsible for handling it was
defined in the machine.config file no longer exists.
To fix the issue, copy the section definition from your old machine.config to your new configuration
file:
Accessing databases
Almost every desktop application needs a database. For desktop, client-server architectures with a
direct connection between the desktop app and the database engine are common. These databases
can be local or remote depending on the need to share information between different users.
There are a lot of technologies and frameworks available to the developer to connect, query, and
update, a database.
The most common examples of databases for Windows Desktop applications are Microsoft Access
and Microsoft SQL Server. If you have more than 20 years of experience programming for the
desktop, ODBC, OLEDB, RDO, ADO and ADO.NET, LINQ and Entity Framework will sound familiar.
ODBC
You can continue to use ODBC on .NET Core since the System.Data.Odbc library is compatible with
.NET Standard 2.0.
OLE DB
OLE DB has been a great way to access various data sources in a uniform manner, but it was based on
COM, which is a Windows-only technology. It is also unsupported in SQL Server versions 2014 and
later. For those reasons, OLE DB will not be supported by .NET Core.
ADO.NET
You can still use ADO.NET from your existing desktop code on .NET Core. You will just need to update
some NuGet packages.
EF Core vs EF 6
There are two versions of Entity Framework (EF): Entity Framework 6 and Entity Framework Core.
The latest version of Entity Framework for .NET Framework is 6.3. With the launch of .NET Core,
Microsoft released a new data access stack based on Entity Framework called Entity Framework Core.
You can use EF 6.3 and EF Core from both .NET Framework and .NET Core, so which should you
choose?
EF 6.3 will be the first version of EF 6 that can run on .NET Core and work cross-platform. In fact, the
main goal of this release is to facilitate migrating existing applications that use EF 6 to .NET Core 3.0.
EF Core was designed to provide a developer experience similar to EF6. Most of the top-level APIs
remain the same, so EF Core will feel familiar to developers who have used EF6.
Although compatible, there are differences on the implementation you should check before making a
decision. (https://docs.microsoft.com/ef/efcore-and-ef6/)
The recommendation is to use EF Core if:
Relational databases
SQL Server
SQL Server has been one of the databases of choice if you were developing for the desktop some
years ago. With the use of System.Data.SqlClient in .NET Framework, you could access versions of SQL
Server, which encapsulates database-specific protocols.
In .NET Core, you can find a new SqlClient fully compatible with the one existing in the .NET
Framework but located in the Microsoft.Data.SqlClient library. You just have to add a dependency for
this package and do some renaming for the namespaces and everything should work as expected.
Microsoft Access
Microsoft Access and its Jet Database Engine has been used for years when the sophisticated and
more scalable SQL Server was not needed. You can still connect to Microsoft Access using the
System.Data.Odbc library.
Consuming services
With the rise of service-oriented architectures, desktop applications begin to evolve from a client-
server model to the three-tier approach. In the client-server approach a direct database connection is
established from the client holding the business logic usually inside a single EXE file. On the other
hand, the three-tier approach establishes an intermediate service layer implementing business logic
and database access allowing for better security, scalability and reusability. Instead of working directly
with datasets of data, the layer approach relies in a set of services implementing contracts and types
objects to implement data transfer.
If you have a desktop application using a WCF service and you want to migrate it to .NET Core, there
are some things to consider.
The first thing is how to resolve the configuration to access the service. Because the configuration is
different on .NET Core , you will need to make some updates in your configuration file. Second, you
will need to regenerate the service client with the new tools present on Visual Studio 2019.
If you find that after migration there are libraries you need that aren’t present on .NET Core, you can
add a reference to Microsoft.Windows.Compatibility and see if the missing functions are there.
If you are using the WebRequest class to perform Web Service calls you may encounter some
differences on .NET Core. The recommendation is to use the System.Net.Http.HttpClient instead.
You need to insert a COMReference structure inside the Project file like:
<ItemGroup>
<COMReference Include=”MSHTML”>
<Guid>{3050F1C5-98B5-11CF-BB82-00AA00BDCE0B}</Guid>
<VersionMajor>4</VersionMajor>
<VersionMinor>0</VersionMinor>
<Lcid>0</Lcid>
<WrapperTool>primary</WrapperTool>
<Isolated>false</Isolated>
</COMReference>
</ItemGroup>
AppDomains
Application domains (AppDomains) isolate apps from one another. AppDomains require runtime
support and are generally quite expensive. Creating additional app domains is not supported on .NET
Core. For code isolation, we recommend separate processes or using containers as an alternative. For
the dynamic loading of assemblies, we recommend the new AssemblyLoadContext class.
To make code migration from .NET Framework easier, .NET Core exposes some of the AppDomain API
surface. Some of the APIs function normally (for example, AppDomain.UnhandledException), some
members do nothing (for example, SetCachePath), and some of them throw
PlatformNotSupportedException (for example, CreateDomain).
Security Transparency
Similar to CAS (Code Access Security), Security Transparency separates sandboxed code from security
critical code in a declarative fashion but is no longer supported as a security boundary.
Use security boundaries provided by the operating system, such as virtualization, containers, or user
accounts for running processes with the least set of privileges.
With the release of Windows 10, Microsoft introduced many innovations to support scenarios like
tablets and touch devices to provide the best experience for users. You can log in with your face using
Windows Hello. You can use a pen to draw or handwrite text that is automatically recognized and
digitalized. You can even run locally customized AI models built on the cloud using WinML.
All these features are enabled for Windows developers through Windows Runtime libraries and you
can take advantage of all of these features in your existing desktop apps because all these libraries are
exposed to both the .NET Framework and .NET Core. You can even modernize your UI with the use of
XAML Islands and improve the visuals and enhance the behavior of your apps.
One important thing to note here is that you don’t need to abandon .NET Framework technology to
follow this modernization path. You can safely stay on .NET Framework and have all the benefits of
Windows 10 without the pressure to migrate to .NET Core. So, you get both the power and the
flexibility to choose your modernization path.
WinRT APIs
Windows Runtime (WinRT) APIs are object-oriented, well-structured application programming
interfaces (APIs) that give Windows 10 developers access to everything the operating system has to
offer. Through WinRT APIs you can integrate functionalities like Push Notifications, Device APIs,
Microsoft Ink, and WinML, and others, on your desktop apps.
In general, WinRT APIs can be called from a classic desktop app. However, two main areas present an
exception to this rule:
UWP Packages
Application Package Identity
UWP apps have a deployment system where the OS manages the installation and uninstallation of
application. That requires the installation to be declarative, meaning that no user code is executed
during install, instead everything the app wants to integrate with the system (protocols, file types,
extensions, etc.) is declared in the application manifest. At deployment time, the deployment pipeline
configures those integration points. The only way for the OS to manage all this functionality and keep
track of it, is for each ‘package’ to have an identity, a unique identifier for the application.
One way to provide an identity is to build an additional packaging project. Inside the packaging
project, you point to the original source code project and specify the Identity information. If you
install the package and run the installed app, it will automatically get an identity, enabling your code
to call all WinRT APIs requiring Identity.
<?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"
Publisher="CN=YOUR COMPANY"
Version="1.x.x.x" />
</Package>
You can check which APIs need a package identity by inspecting if the type that contains the API is
marked with the DualApiPartition attribute. If it is present, you can call it from a traditional desktop
app without an identity. If not present, you must provide an identity using the process described
above.
https://docs.microsoft.com/windows/desktop/apiindex/uwp-apis-callable-from-a-classic-desktop-app
Benefits of packaging
Besides giving you access to these APIs, you get some additional benefits by creating a Windows App
package for your desktop application including:
• Streamlined deployment. Apps have a great deployment experience ensuring that users can
confidently install an application and update it. If a user chooses to uninstall the app, it is
removed completely with no trace left.
• Automatic updates and licensing. Your application can participate in the Microsoft Store's
built-in licensing and automatic update facilities. Automatic update is a highly reliable and
efficient mechanism; the changed parts of files are downloaded during an update.
• Increased reach and simplified monetization. If you choose to distribute your application
through the Microsoft Store you reach millions of Windows 10 users.
• Add UWP features. You can add UWP features to your app's package at your own pace.
Prepare for packaging
Before proceeding to package your desktop application, there are some points you must address
before starting the process. Your application must respect any of the Microsoft Store rules and
policies and run in the UWP application model. For example, it must run on the .NET Framework 4.6.2
or later. Any writes to the HKEY_CURRENT_USER registry hive and the AppData folder will be virtualized
to a user-specific app-specific location.
Packages that you create for your desktop application are desktop-only, full-trust applications, and
aren’t sandboxed, although there is lightweight virtualization applied to the app for writes to HKCU &
AppData. This allows them to interact with other apps the same way classic desktop applications do.
• Installation
After deployment, package files are marked read-only and heavily locked down by the
operating system. Windows prevents apps from launching if these files are tampered with.
• File system
The OS supports different levels of file system operations for packaged desktop applications,
depending on the folder location.
When trying to access the user’s AppData folder the system creates a private per-user, per-
app location behind the scenes. This creates the illusion that the packaged application is
editing the real AppData when it is actually modifying a private copy. By redirecting writes this
way, the system can track all file modifications made by the app. It can then clean all those
files when uninstalling reducing system “rot” and providing a better application removal
experience for the user.
• Registry
App packages contain a registry.dat file, which serves as the logical equivalent
of HKLM\Software in the real registry. At runtime, this virtual registry merges the contents of
this hive into the native system hive to provide a singular view of both.
All writes are kept during package upgrade and only deleted when the application is
uninstalled.
• Uninstallation
When the user uninstalls a package, all files and folders located under C:\Program
Files\WindowsApps\package_name are removed, as well as any redirected writes to AppData
or the registry that were captured during the process.
Let’s take an existing WPF sample app that reads files and shows its contents on the screen. The goal
will be to display a Toast Notification when the application starts.
First, you should check in the below link whether the Windows 10 API that you will use requires a
Package Identity:
https://docs.microsoft.com/windows/apps/desktop/modernize/desktop-to-uwp-supported-api
Our sample will use the Windows.UI.Notifications API that requires a packaged identity:
You need to create a ShowToastNotification method that will be called on application startup. It just
builds a toast notification from an XML pattern:
Although the project builds, there are errors because the Notifications API requires a Package Identity,
and we didn't provide it. Adding a Windows Packaging Project in the Solution will fix it:
Next step is to add the WPF application to the Windows Packaging Project by adding a project
reference:
Next step is to set the WPF Project as the startup Project in the solution configuration. You can press F5
to compile and build and see the results.
Select the sideloading option to deploy the app from your machine:
You can image your Win32 app with your standard controls and among them an “island” of UWP UI
containing controls from the modern world. The concept is similar as having an iFrame inside a web
page that shows content from a different page.
Besides adding functionality from the Windows 10 APIs, you can add pieces of UWP XAML inside of
your app using XAML Islands.
Windows 10 1903 update introduces a set of APIs that allows hosting UWP XAML content in Win32
windows. Only apps running on Windows 10 1903 and above can use XAML Islands.
In 2015, along with Windows 10, UWP was born. The Universal Windows Platform (UWP) allows you to
create apps that work across Windows devices like Xbox, Mobile, and Desktop. One year later,
Microsoft announced Desktop Bridge (formerly known as Project Centennial). Desktop Bridge is a set
of tools that allowed developers to bring their existing Win32 apps to the Microsoft Store. More
capabilities were added in 2017, allowing developers to enhance their Win32 apps leveraging some of
the new Windows 10 APIs, like live tiles and notifications on the action center. But still, no new UI
controls.
How it works
The Windows 10 1903 update introduces several XAML hosting APIs. Two of them are
WindowsXamlManager and DesktopWindowXamlSource.
The WindowsXamlManager class handles the UWP XAML Framework. Its method
InitializeForCurrentThread loads the UWP XAML Framework inside the current thread of the Win32
app.
The DesktopWindowXamlSource is the instance of your XAML Island content. It has the Content
property which you are responsible for instantiating and setting. The
DesktopWindowXamlSource renders and gets its input from an HWND. It needs to know to which
other HWND it will attach the XAML Island’s one, and you are responsible for sizing and positioning
the parent’s HWND.
WPF or Windows Forms developers don’t usually deal with HWND inside their code, so it may be hard
to understand and handle HWND pointers and the underlying wiring stuff to communicate Win32 and
UWP worlds.
The Windows Community Toolkit has a set the XAML Islands .NET wrappers for WPF or Windows
Forms that make easier to use XAML Islands. These wrappers manage the HWNDs, the focus
management, among other things. Windows Forms and WPF developers should use these wrappers.
The Windows Community Toolkit offers two types of controls: Wrapped Controls and Hosting Controls
Wrapped Controls
These wrapped controls are UWP controls wrapped into Windows Forms or WPF controls, hiding UWP
concepts from the developer. These controls are:
o WebView and WebViewCompatible
o InkCanvas and InkToolbar
o MediaPlayerElement
o MapControl
Add the Microsoft.Toolkit.Wpf.UI.Controls package to your project, include the reference to the
namespace and start using them.
<Window
...
xmlns:uwpControls="clr-
namespace:Microsoft.Toolkit.Wpf.UI.Controls;assembly=Microsoft.Toolkit.Wpf.UI.Controls">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
Hosting Controls
Most of the built-in controls, as well as 3rd party controls, can be integrated into Windows Forms and
WPF as a “XMAL Island” of fully functional UI. The WindowsXamlHost control for WPF and Windows
Forms allows doing this.
For example, to use the WindowsXamlHost control in WPF, you just need to add the
Microsoft.Toolkit.Wpf.UI.XamlHost package provided by Windows Community Toolkit. Once you have
placed the WindowsXamlHost into your UI code, you just need to specify which UWP type you want
to load and you can choose to use a wrapped control like a Button or a more complex one composed
by several different controls.
Here is a sample code snippet that shows how to add a UWP Button:
<Window
...
xmlns:xamlhost="clr-
namespace:Microsoft.Toolkit.Wpf.UI.XamlHost;assembly=Microsoft.Toolkit.Wpf.UI.XamlHost">
<xamlhost:WindowsXamlHost x:Name="myUwpButton"
InitialTypeName="Windows.UI.Xaml.Controls.Button" />
It is better to have a single, bigger, XAML Island containing a custom composite control than to have
several islands each with one control.
One of the core features of XAML is the binding markup extension and it works between your Win32
code and the island. For instance, you can bind a Win32 Textbox with a UWP Textbox. One important
thing to consider is that these bindings are one-way bindings, from UWP to Win32, so if you update
the Textbox inside the XAML Island the Win32 Textbox will be updated, but not the other way around.
https://docs.microsoft.com/windows/apps/desktop/modernize/host-standard-control-with-xaml-
islands
A XAML custom control is a control (or user control) created by you or by 3rd parties (including WinUI
2.x controls). To host a custom UWP control in a Windows Forms or WPF app, you'll need to use the
WindowsXamlHost in your app. Additionally, you must create a UWP app project that defines a
XamlApplication object.
Your WPF (or Windows Forms) project must have access to an instance of the
Microsoft.Toolkit.Win32.UI.XamlHost.XamlApplication class provided by the Windows Community
Toolkit. This object acts as a root metadata provider for loading metadata for custom UWP XAML
types in assemblies in the current directory of your application. The recommended way to do this is to
add a Blank App (Universal Windows) project to the same solution as your WPF (or Windows Forms)
project and revise the default App class in this project.
https://docs.microsoft.com/windows/apps/desktop/modernize/host-custom-control-with-xaml-
islands
Besides the built-in Windows 10 controls that come with Windows, additional controls are included in
the Windows UI Library (WinUI 2). WinUI 2 provides official native Microsoft UI controls and features
for Windows UWP apps and these controls can be used inside of XAML Islands.
WinUI 2 is open source and you can find information at: https://github.com/microsoft/microsoft-ui-
xaml
The following article demonstrates how to host a UWP XAML control from the WinUI 2 library:
https://docs.microsoft.com/windows/apps/desktop/modernize/host-custom-control-with-xaml-
islands
If you are developing a new Windows App, a UWP App is probably the right approach.
Starting with WinUI 2 in 2018, Microsoft started shipping some new XAML UI controls and features as
separate NuGet packages that build on top of the UWP SDK.
This means that the XAML framework will now be developed on GitHub and ship out of band
as NuGet packages. This includes the XAML Islands APIs that will support loading the WinUI 3
platform on Win32 apps.
The existing UWP XAML APIs that ship as part of the OS will no longer receive new feature updates.
They will still receive security updates and critical fixes according to the Windows 10 support lifecycle.
The Universal Windows Platform contains more than just the XAML framework (e.g. application and
security model, media pipeline, Xbox and Windows 10 shell integrations, broad device support) and
will continue to evolve. All new XAML features will just be developed and shipped as part of WinUI
instead of the OS.
As you can see, WinUI 3 is the evolution of UWP XAML and it works naturally within the UWP app
model and all its requirements (MSIX packaged ID, sandbox, CoreWindow, etc.). To use just WinUI 3 in
a Win32 app model, the WinUI content should be hosted by another UI Framework (Windows Forms,
WPF, etc.) using WinUI XAML Islands. This is the right path if you want to evolve your app and mix
WinUI 3 will address this critical feedback adding WinUI in desktop apps. This will mean that Win32
apps can use WinUI 3 as standalone UI Framework, without the need to load Windows Forms or WPF.
WinUI 3 will let developers easily mix and match the right combination of:
We present a well-structured process you can follow and the most important things to consider on
each step.
We then document a step-by-step migration process for a sample desktop application, both with
Windows Forms and Windows Presentation Foundation versions.
1. Preparation: You must understand the dependencies of the project to have an idea of what is
ahead. In this step, you take the current project into a state that simplifies the startup point
for the migration.
2. Migrate Project File: .NET Core projects use the new SDK style projects. You need to create a
new project file with this format or update the one you must use the SDK style.
3. Fix Code and Build: Get the code compiling in .NET Core, addressing API differences
between .NET Framework and .NET Core or in third party packages used by your app.
Additionally, regenerate any generated code like WCF client-code.
4. Run and Test: There are differences that don’t show up until run-time, so you need to test
your app to be sure everything works as expected.
Once you have migrated the package references you must check each reference for compatibility. If
you go to nugget.org you can explore the dependencies of each NuGet package your application is
using. If it has .NET Standard dependencies, then it’s going to work on .NET Core because it depends
on .NET Standard. Here you can see a screenshot showing the dependencies for the Castle.Windsor
Package:
To check out package compatibility, you can use the tool http://fuget.org that offers a more detailed
information about versions and dependencies.
Maybe the versions of the packages referenced by the project are older versions that don’t support
.NET Core but you can find newer versions that do support it. Therefore, updating packages to newer
versions is in general a good recommendation although you must consider that this can introduce
some breaking changes forcing you to update your code to keep it compiling well.
What happens if you don’t find a compatible version? What if you just don’t want to update the
version of a package because of these breaking changes? Don’t worry because it is possible to
depend on .NET Framework packages from a .NET Core application. You must test this extensively
because it can cause runtime errors if the external package calls an API that is not available on .NET
Core. This is great news when you are using an old package that is not going to be updated and you
just can retarget to work on the .NET Core.
Since APIs surfaces in .NET Framework and .NET are similar but not identical, you must check which of
those APIs are available on .NET Core and which are not. You can use the .NET Portability Analyzer
tools to surface APIs used that aren’t present on .NET Core. It looks at the binary level of your app and
extracts all the APIs that are called showing the ones that aren’t available on your target framework,
.NET Core 3.0 in our case.
https://docs.microsoft.com/dotnet/standard/analyzers/portability-analyzer
The most interesting result from this tool refers to differences in your own code and not in external
packages that you cannot change. Remember you should have updated most of these packages to
make them work with .NET Core.
In most of the cases you will want to update your existing project to the new .NET Core format, but be
aware that you can also create a new project while maintaining the old one. The main drawback from
updating the old project is that you lose designer support, which may be important to you. If you
want to keep using the designer, you must create a new .NET Core project in parallel with the old one
and share assets. When it is time to modify UI elements in the designer you can switch to the old
project to do that, and since assets are linked there will be updated in the .NET Core project.
.NET Core SDK style project are a lot simpler that .NET Framework and apart from the mentioned
PackageReference stuff, you will not need to do much more. SDK style adds all necessary files
underneath project file location like .cs and .xaml files without the need to explicitly include them in
the .csproj.
Assembly.info considerations
For .NET Core projects AssemblyInfo.cs file gets automatically generated, so if you happen to have this
file already in your project, you will get errors. To fix this you can either delete your existing
AssemblyInfo.cs file or keep it and disable auto generation by adding this entry to the .NET Core
project file:
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
Resources
Embedded resources are included automatically but resources are not, so you need to migrate those
to the new .csproj file.
Packages References
In a .NET Framework application, all references to external packages are declared in the
packages.config file. In .NET Core, there is no longer the need to use the packages.config file. Instead,
the new PackageReference format inside the project file is used to pull in NuGet dependencies.
You must upgrade from one format to another. You can let Visual Studio do the work for you by
right-clicking on the packages.config file and selecting the “Migrate packages.config to
PackageReference” option. Or you can do it manually by taking the dependencies contained in the
packages.config file and pasting them into the project file with the PackageReference attribute.
In case your applications depend on APIs that aren’t available on .NET Core like Registry, ACLs, WCF
you have to include a reference to the Microsoft.Windows.Compatibility package to add these
Windows-specific APIs. They work on .NET Core but aren’t included as they aren’t cross-platform.
If you need different execution paths when targeting .NET Framework and .NET Core, you should use
#if directives to keep the same code base for both targets.
• AppDomains
• Remoting
• Code Access Security
• WCF Server
• Windows Workflow
Therefore, it is time to look for a replacement for those if you use them.
If your application uses some autogenerated code like, for example a WCF client, you may need to
regenerate this code to target .NET Core. Sometimes you can find some missing references since it
may not be included as part of the basic .NET Core assemblies. Using a tool like .NET API Catalog
(https://apisof.net/) you can easily locate the assembly the missing reference lives in and add it from
NuGet.
As a rule, we have stated that you should update every single package to be compatible with .NET
Core. However, you may find that targeting a compatible version of an assembly just does not pay off.
If the cost of change is not acceptable, you can consider rolling back package versions, keeping the
ones you used on .NET Framework. Although they may not target .NET Core, they should work unless
they call an unsupported API.
In this final step, you may find a variety of issues depending on the complexity of your application and
the dependencies and APIs you are using.
Another reason for errors is the use of BeginInvoke and EndInvoke; these aren’t supported on .NET
Core. The reason they aren’t supported on .NET Core is that they have a dependency on Remoting,
which does not exist on .NET Core. To solve this issue, try to use Async when available or Task.Run.
You can use compatibility analyzers to let you identify APIs and code patterns that can potentially
cause problems at run-time with .NET Core. You can go to http://github.com/dotnet/platform-compat
and use the Roselyn analyzers.
This application shows a product catalog and allows the user to navigate, filter, and search for
products. From an architecture point of view the app relies on an external WCF service that serves as a
façade to a back-end database.
You can see the main application window in the following picture:
If we open the .csproj file we can something like this, the .NET Framework project file:
Now we can update the .csproj file. We will delete all the content and replace it with:
We are done updating the project file, save and reload it. Now the project is targeting the .NET Core.
If we compile the project at this point, we find some errors related to the WCF client reference. Since
this is autogenerated code we must regenerate it to target .NET Core.
We can delete the Reference.cs file and add generate a new Service Client.
This will open the Connected Services window where we select the Microsoft WCF Web Service
option.
If we have the WCF Service in the same solution, we can choose to select the Discover option instead
of specifying a service URL.
If we compile again, we see many errors coming from .cs files inside the Helper folder. This folder was
present in the .NET Framework version but not included in the old .csproj. But with the new SDK
project style every code file present underneath the project file location is included by default,
meaning that the new .NET Core project tries to compile the files inside the Helper folder. Since it is
not needed, we can safely delete it.
We compile again but when we execute the application, we see no images of products. The problem
is that now the path to the files has changed slightly and we need to add another level of depth in the
path, updating from:
catalogItems.Picturefilename;
to
catalogItems.Picturefilename;
This application uses a local SQL Server Express database to hold the product catalog information.
This database is accessed directly from the WPF application.
We must first update the .csproj file to the new SDK style used by.NET Core. To do this we follow the
same steps described in the Windows Forms migration, we unload the project, open the .csproj file,
update its contents, and finally reload the project.
In this case, we delete all the content of the .csproj file and replace it with:
<Project Sdk="Microsoft.NET.Sdk.WindowsDesktop">
<PropertyGroup>
<OutputType>WinExe</OutputType>
<TargetFramework>netcoreapp3.0</TargetFramework>
<UseWPF>true</UseWPF>
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
</PropertyGroup>
</Project>
Since we have deleted all the .csproj contents we have lost a project reference present in the old
project. We just need to add this line to .csproj to include it:
<ItemGroup>
<ProjectReference Include=”..\eShop.SqlProvider\eShop.SqlProvider.csproj” />
<ItemGroup>
Alternatively, we can let Visual Studio help us by clicking on Add Reference option and select the
project from the solution:
Once we do this the application compiles and executes as expected on .NET Core.
In this chapter, we talk about MSIX the brand-new technology from Microsoft that tries to capture the
best of previous technologies to provide a solid foundation for the packaging technology of the
future.
Companies need a way to break this packaging cycle with three independent cycles:
• OS updates
• Application updates
• Customization
This radical change leads us to the new and modern IT lifecycle depicted in the following picture:
Developers create the app and generate an MSIX package that IT pros can consume and configure
without the need of repackaging.
With MSIX, we get one installer technology with all these features.
MSIX provides a predictable, reliable, and safe deployment of your app. The declarative method
contained in the package manifest lets the OS keep track of every asset your application needs. It also
provides a true clean uninstall with no side effects.
MSIX is optimized to reduce the footprint the application has on the user’s machine. It creates a single
instance storage of your files, meaning that if you have two different packages with the same DLL, it is
not installed twice. The platform takes care of that because it knows all the files that are installed by
an app thanks to its declarative nature. It also allows you to have different versions of a DLL working
side by side.
With the use of Resource packages, you can easily create multilingual apps and the OS takes care of
installing the ones that are used.
Network optimization
MSIX detects the differences on the files at the byte-level enabling a feature called Differential
Updates. What this means it that only the updated bytes are downloaded on application updates.
Through optional packages feature you achieve componentization on your app deployment so you
can download them when needed.
The AppManifest declares the versioning, device targeting, and an identify every application in a
standard way. It also provides a way to sign your assets providing a solid security foundation.
OS Managed
The OS handles install, update, and removal of an application. Applications are installed per user but
downloaded only once, minimizing the disk footprint.
With the use of digital signatures, you can guarantee that you don’t install an application from an
untrusted source. MSIX also prevents tampering because it keeps a record of file hashes and detects
when the file has been modified after installation.
One of the coolest things about MSIX is that it works for the entire application catalog, Windows
Forms, WPF, MFC/ATL, Delphi, ClickOnce, the Microsoft Store, even xCopy deployments, you can use
the same MSIX package.
Tools
Windows Application Packaging Project
You can use the Windows Application Packaging Project project in Visual Studio to generate a
package for your desktop app. Then, you can publish that package to the Microsoft Store or sideload
it onto one or more PCs.
The MSIX Packaging Tool enables you to repackage your existing Win32 applications in the MSIX
format. It offers both an interactive UI and a command line interface for packaging your app and gives
you the ability to convert an application without having the source code.
The Package Support Framework is an open source kit that helps you apply fixes to your existing
win32 application when you don’t have access to the source code, so that it can run in an MSIX
container. The Package Support Framework helps your application follow the best practices of the
modern runtime environment.
App Installer
App Installer allows for Windows 10 apps to be installed by double clicking the app package. This
means that users don’t need to use PowerShell or other developer tools to deploy Windows 10 apps.
The App Installer can also install an application from the web along with optional packages.
You will see the structure of the packaging project and note a special folder called Applications. Inside
this folder is where you specify which are the applications you want to include in the package, you can
include more than one.
Right-click on the Applications folder and select the Windows Forms project we want to pack that is
present in the Visual Studio solution.
If you open the code for the Package.appxmanifest you can see a couple of interesting things.
Second is the Capabilities node. You can find all the requirements the application needs, paying
special attention to the <rescap:Capability Name=”runFullTrust” /> element which tells the OS to run
the app in full trust mode, as is common with a Win32 application.
With this, you have the fully integrated Windows 10 install and uninstall experience that MSIX
provides.
But, how do you deploy the MSIX package to another machine? Right-click on the packaging project,
select the Store menu, and then click on Create App Packages option.
Then, choose between creating a package to upload to the store, or, as is common with most
modernization scenarios, choose “I want to create packages for sideloading”.
The final step is to declare where you want to deploy the final installation assets.
https://docs.microsoft.com/windows/msix/desktop/desktop-to-uwp-packaging-dot-net
Using a combination of Windows 10 features and MSIX packages, you can provide a great update
experience for your users. In fact, the user does not need to be technical to benefit from a seamless
application update experience.
You can configure your updates to interact with the user in two different ways:
• User prompted updates: The OS shows a nice auto generated UI to notify the user the
application is about to install. It builds this UI based on the properties you specify on your
installation files.
• Silent updates in the background. With this option, your users don’t need to be aware of the
updates.
When you use this type of deployment, a special file is created named .appinstaller. This simple file
contains the following sections:
In combination with this file, Microsoft has designed a special URL protocol to launch the installation
process from a link:
<a href="ms-appinstaller:?source=http://mywebservice.azureedge.net/MyApp.msix"> Install app package </a>
This protocol works on all browsers and launches the installation process with a good user experience
on Windows 10. Since the OS manages the installation process, it is aware of the location the
application was installed from and tracks all the files affected by the process.
The process to distribute a new version of your app is simple. After you have generated the new MSIX
package, move it to the deployment server. Next, edit the .appinstaller file to reflect this changes,
mainly the version and the path to the new MSIX file. The next time the user launches the application
the system is going to detect the change and download the files for the new version in the