Crossing the Windows Desktop Bridge

For a recent project we build a WPF application to run on the windows 10 platform, but we were hoping to take advantage of some of the new hotness that didn't exist in Windows when WPF was created.  Enter the Windows Desktop Bridge, or Project Centennial depending on how you google it.

For the unfamiliar, this technology shipped with MSFT's Anniversary Update in 2016 and it allows your beloved and battle-tested Win32 applications to package and deploy to the Windows Store.  What this means is your Win32 app gets an appxmanifest file that fully supports store assets, live tiles, protocol activation, UWP API's, AppService connections, and much, much more.   It's all here in this pamphlet.

Ok, so you're sold on why this technology is helpful; and your boss is on board; but HOW do you get started?  In the rest of this post I'm going to point out a few key things to keep in mind when you get going.  Hopefully this will save you some time.

The Abstract:

So first, I suggest you be realistic about your expectations and your project plan.  What are your goals here?  Do you want to move to UWP or do you just want to take advantage of some of the cool new features in Windows 10?  That decision is project-specific and will determine your strategy.  Some key things to consider are:

  • Where are you starting on the bridge?  There are several ways to convert an app including running command line utilities against an MSI, manually converting your app, or using a visual studio extension to build your current project directly.
  • How is your Win32 app abstracted?  Can you easily refactor Win32 API's into their WinRT counterparts? File system access migrating from System.IO namespaces to Windows.Storage namespaces is a great example.
  • How does your application interact with the operating system?  Are you caching global app settings in restricted registry keys like HKLM?  Do you depend on writing to specific space on the hard drive, or generating code?  Do you do significant Pinvoke into Windows or 3rd party Dll's that may do restricted things?  There is a big list of things to consider when preparing to use the bridge.
  • What will it take to migrate your UI layer?  Do you even need to migrate the UI layer?  UWP brings great benefits such as consolidated Input, RelativeLayout, and Touch-Friendly controls; but even refactoring a well-designed WPF Presentation layer can be a challenge.
  • Are you working on a greenfield project that just needs access to some legacy components?  If So, building a UWP front-end with an App Service connection may be an excellent way to take advantage of both worlds.

Next, I suggest you read the blog posts and run some samples.  Like most things Microsoft, it's pretty well documented; but you'll have a heck of a time finding it.  Check out this curated list:

The Secret Sauce:

Now that we've thoroughly wasted our day looking at other people's code.  Let's spend some time talking about how to stay productive when writing your own code:

Use WinRT API's Whenever Possible

Most people don't know you can add Windows Runtime API's to Win32 projects, and this is poorly documented.  This CodeProject article describes the process in detail.  Basically, you need to modify the .xxproj file to add a TargetPlatformVersion element, and then add the appropriate references to the correct windows dll's.

It's also important to note that not all API's are available.  Fortunately there is a list.  Obvious things like UWP XAML and Contract Activation do not work, but there are some nice pieces that can be shared, like the SWindows.Web Namespaces.

Abstract your Runtime Code

Depending on your roadmap and migration strategy, you may be planning to migrate your Win32 app to a full UWP app.  In this case, it makes sense to keep your Runtime code shareable.  In practice, we have used two methods to abstract runtime code: Shared Projects and Runtime Components.  Both have strengths and weaknesses.

Shared Projects make it easy to use compiler directives inside a file for different platforms.  In some cases this is preferable, especially if everything is well encapsulated and your class API's don't have dependencies on platform objects.

Runtime Components generate a separate .winmd file and can be consumed by different processes.  We use this method to share logic between foreground and background processes.  The background tasks sample shows how to use a runtime component in a win32 app.

Consider What Full-Trust Means

The Runtime environment is designed to run sandboxed, but as you have learned by reading the extensive documentation referenced above, Bridge applications run in a Full-Trust mode.  This means you should give special consideration to the security footprint of your app, and your users' expectations.



WHAT'S NEXT:

I hope this post gives you a big head start on your project.  It seems there are never-ending ways to use this tech and also some fairly significant limitations.  Let us know in the comments if you have some new insights, or some war stories to share!