Mike Taulty's Blog
Bits and Bytes from Microsoft UK
Windows/Phone 8.1: “More Universal” WinRT Components

Blogs

Mike Taulty's Blog

Elsewhere

Archives

I’ve been puzzling a little over the project templates in Visual Studio that let you build a “Universal Windows Runtime Component”. These are C#/C++ templates and, frankly, I’ve built components with these templates in C# already for background tasks but in doing so I didn’t really think the whole thing through and so I’m adding some notes here that I made when I went back to look at it a little more closely and perhaps think a little bit more rather than just writing code.

This post is just some notes – some of the things that get mentioned in this post would be new in the sense that;

  • Universal projects are new.
  • HTML/JavaScript projects are new for Windows Phone.
  • WinRT components in .NET for Windows Phone are new.

and some of the things mentioned were already perhaps around before Windows Phone 8.1 preview and Visual Studio 2013 Update 2.

Aren’t WinRT Components Already Universal?

For a Windows/Phone 8.1 app, the main set of APIs that you call are WinRT APIs with a caveat around that being a bit different if you are building an app with Silverlight for 8.1 where you have more “Silverlight .NET” APIs at your disposal.

Classes like MessageDialog and it’s methods like ShowAsync are WinRT APIs that are available to a developer writing JavaScript;

            var nsPopups = Windows.UI.Popups;

            var dialog = new nsPopups.MessageDialog("Hello World");

            var promise = dialog.showAsync();

            promise = promise.then(
              function () {
                // the user has dismissed the dialog. do something else.
              }
            );

            promise.done();

or writing C++ or C++/CX; (including ppltasks.h and bringing in the concurrency and Windows::UI :: Popups namespaces);

	MessageDialog^ dialog =
		ref new MessageDialog("Hello World");

	auto task = create_task(dialog->ShowAsync());

	task.then(
		[](IUICommand^ command) -> void
		{
			// the user has dismissed the dialog, do something else.
		}
	);

or writing C#;

      MessageDialog dialog = new MessageDialog("Hello World");

      var command = await dialog.ShowAsync();

      // the user has dismissed the dialog, do something else.

This is one of the strengths of these WinRT APIs – they’re “projected” into these different technologies so that a developer can try to make use of the skills that they have while not getting cut off from some set of APIs that another developer using a different technology might have access to.

.NET is one of the technologies that can be used to make a custom WinRT component (C++ being the other) and a custom WinRT component is consumed by being “projected” into these different programming environments which means that the component has to be written a certain way (in terms of types and so on) such that the projection can work when the consuming environments have so many differences.

A .NET component and a WinRT component are not interchangeable or in any way the same thing  and there’s a good article on MSDN by Jeremy Likness on custom WinRT components if you haven’t dug in there before but, in generally, most of your .NET code is going to be about building .NET components and libraries rather than building WinRT components.

In writing .NET libraries, it’s possible to make them into “Portable Class Libraries” which means that they target and can be referenced from a number of platforms and that the code within the portable library has to stay within the intersection of the APIs/types available on all those targeted platforms.

While you wouldn’t typically write WinRT components, there are times when you would and those times might include;

  1. When you have to. For example – writing a background task involves writing a custom WinRT component.
  2. You have a component that you want to make available to the multiple implementation technologies for Windows/Phone. For example – maybe you own a file-based database technology. You perhaps want to package that in a way such that it could be used by a developer of any Windows/Phone app and so you package it as a WinRT component to let developers do that and, in doing so, you have to live by the type system of WinRT and follow the rules (you can get an idea of what that looks like from my old post here where I played with the ESE database API back in 2012). A developer can then use your component whether they are working in JavaScript/.NET/C++ and the system does the work to marshal types back/forth across the barriers between the type system of the component and the type system of the code that’s using it.

In that latter sense, a WinRT component is in some senses already “Universal” – it has “Universal” appeal to JavaScript/.NET/C++ code but that’s not the usage of “Universal” that’s generally being applied to Windows/Phone projects.

Being “More Universal”

A WinRT component’s implementation could also be “More Universal” in the sense of building a component that not only can be used across the JavaScript/.NET/C++ environments but, also, that can be used across both Windows and Windows Phone 8.1.

Visual Studio has project templates for WinRT components that target this “Universal” set of platforms (it also has WinRT component templates for targeting Windows and Windows Phone separately).

I can illustrate that with something that’s a bit pointless but let’s me play with the different project types – some code that wraps up that MessageDialog call that we just used.

Let’s say we’re writing a WinRT component in .NET and want to consume that component in JavaScript. What I’ve built here is 5 projects;

image

The main app is named JavaScriptApp and is a “Universal” app so there’s a project for Windows 8.1, one for Phone 8.1 and a Shared project which (from the template) just contains a default.js file.

Then there are 4 other projects here;

  • PortableLibrary which is a .NET library project created with the “Universal” template so it can target both Windows/Phone 8.1
  • PortableComponent is a WinRT component project created with the “Universal” template so it can target both Windows/Phone 8.1
  • PhoneOnlyComponent is a WinRT component project created with the “Windows Phone” template.
  • WindowsOnlyComponent is a WinRT component project created with the “Windows” template.

The only code that I wrote is in the portable library project where we have this piece of slightly pointless code just to “do something”;

namespace PortableLibrary
{
  using System;
  using System.Threading.Tasks;
  using Windows.UI.Popups;

  public static class PointlessPortableDialog
  {
    public static async Task<IUICommand> ShowAsync(string message)
    {
      MessageDialog dialog = new MessageDialog(message);
      var result = await dialog.ShowAsync();

      return (result);
    }
  }
}

and I’ve then referenced the PortableLibrary project from the PortableComponent, PhoneOnlyComponent, WindowsOnlyComponent projects and each of those projects contain this duplicated code file;

namespace PortableComponent
{
  using PortableLibrary;
  using System;
  using Windows.Foundation;
  using Windows.UI.Popups;

  // Sealed because this is WinRT.
  public sealed class Component
  {
    // IAsyncOperation because this is WinRT.
    public static IAsyncOperation<IUICommand> ShowAsync(string message)
    {
      // We call into the portable .NET library.
      return (PointlessPortableDialog.ShowAsync(message).AsAsyncOperation());
    }
  }
}

so they are each just defining a component called Component and they each implement that by calling out to the portable .NET code.

Now, this opens up an interesting mixture of which project in Visual Studio can reference which other project – clearly, all the WinRT component projects can reference the portable .NET class library as I’ve already done it.

For the JavaScript projects I can;

  1. Reference the WindowsOnlyComponent or the PortableComponent from the Windows project.
  2. Reference the PhoneOnlyComponent or the PortableComponent from the Phone project.

Other combinations aren’t going to work – i.e. the Windows project can’t reference the PhoneOnlyComponent.

Let’s say that I reference the PortableComponent from both the Windows & Phone sides of the universal projects as below;

image

and then in the “shared” default.js file I could write some code like this;

                  var promise = PortableComponent.Component.showAsync("Hello World");

                  promise.done();

and that works absolutely fine on both Windows and Windows Phone 8.1.

When I think about the technologies involved in that, it does make my head spin a little bit. We’re writing JavaScript and that JavaScript is going to run both on Windows/Phone 8.1 as a native app and because it’s a native app it has access to this API brought in by the referenced PortableComponent component. That component is written in .NET and so it will need just-in-time compiling for when it runs on my x86 PC so we’ll be running x86 code at that point but that’ll change when we debug on a Phone device.

So, setting my debugger up to debug managed code and then setting a breakpoint in my component’s ShowAsync method on my Windows x86 laptop I get;

image

and if I set the same breakpoint on my phone then I get;

image

and this stack of technologies from HTML UI –> JavaScript –> WinRT –> portable .NET code –> x86/ARM makes my head spin a bit.

I can launch that debugger on the Phone or the emulator because my build configuration is set to AnyCPU and both the JavaScript and .NET projects can support that notion of “Any CPU” whereas as soon as I introduce any native code, that’s no longer possible.

That also has implications for how these bits are packaged.

“Packaging” of the Component

One of the nice things about building this WinRT as a .NET component is the way in which that component gets packaged. If I go and take a look at the output folders of the PortableComponent project;

image

then I have the standard Debug/Release builds and within either of those folders I have the same number/names of files;

image

3 of those files relate to the portable library that I’ve taken a dependency on but the actual WinRT component files are the .pdb, the .pri (resources) and the .winmd file. Because this is .NET code, the .winmd file is a combination of code+metadata in that the .winmd is both a description of the component and the component itself.

If I was to add a C++ WinRT component into my project then, again, I can use a “Universal” project to do that;

image

and that “Universal” project is, as you might expect, a bit different from the .NET one in that it contains 2 projects with a shared folder rather than the one project you’d get in .NET;

image

all the code (i.e. the one class file/header file) is in the Shared project and the other two “head” projects for Windows/Phone are bringing in that code and compiling it in each of those environments. Looking at the properties for the Windows project you can see some of that;

image

in that it’s bringing in libraries and include folders from the Windows SDK and if we look at the properties for the Windows Phone project you can see that it’s looking for things in the Windows Phone SDK instead (one example highlighted below);

image

and so these 2 projects are (at least at the moment) really just providing 2 ways of compiling the source code – once for Windows and once for Windows Phone.

When I add this project in to Visual Studio, it automatically moves the active configuration from AnyCPU to a Mixed Platforms configuration;

image

because I “guess” that an “AnyCPU” configuration isn’t meaningful for building those C++ projects as they really need to know what compiler they are using.

As you see in the .NET tooling for shared projects, Visual Studio has C++ support for this kind of “shared” development and so if I try and use a Windows Phone 8.1 specific class (ContentDialog is my favourite for this) then the code looks “sort of fine” in the Windows Phone view;

image

but those squiggles are actually trying to indicate that the Windows side of the house is unhappy and I can get a better sense of that “unhappiness” by switching the navigation bar to a Windows context;

image

where I can see that the Windows project isn’t going to build because it doesn’t know what a ContentDialog is and so the tooling and compiler is doing the right thing here to tell me that I’m trying to write “shared” code.

Going back to “packaging”, if I write some code similar to what I had in my original .NET WinRT component;

#include "pch.h"

using namespace Windows::Foundation;
using namespace Windows::UI::Popups;
using namespace Platform;

namespace PortableComponentCpp
{
	public ref class Component sealed
	{
	public:
		static IAsyncOperation<IUICommand^>^ Component::ShowAsync(String^ message)
		{
			MessageDialog^ dialog = ref new MessageDialog(message);

			return(dialog->ShowAsync());
		}
	private:
		Component() {};
	};
};

and then if I build this without changing any build settings in Visual Studio then I still see Debug/Release folders as for the .NET component project;

image

but if I take a look inside one of those folders (Debug) then I see;

image

And in one of those folders (Windows) I see;

image

and so, once again, I’ve got a .winmd file but this is purely about metadata/description. There’s no code in there like there would be in the .NET case. The code’s in the .dll file (I’ve also got .pri, .pdb, .lib files).

The code’s also real code rather than intermediate language.

If I switch my JavaScript projects so that they are both referencing this project rather than the .NET one then it’s a slightly different experience than adding a reference to the .NET component because I’ve got 2 choices in terms of what to add – the yellow highlight below shows the 2 possible outputs of the C++ component project whereas the red highlight shows the one output of the .NET component project;

image

If I do try and mistakenly reference the WindowsPhone output from a Windows project then I get an error dialog;

image

but if I add the references in the right way then that works out fine.

At that point, the Windows project will debug just fine and the Windows Phone project will debug on the emulators but it won’t offer me the option to debug on my Phone;

image

because I’m still running in that “Mixed Platforms” configuration. To debug on the Phone I’m going to have to build ARM code and if I change my configuration to be ARM then I see some more folders show up in the build outputs;

image

and now I’ve got build outputs for Windows/Phone for ARM (naturally, I’d need the Windows ARM binaries for a device like Surface RT) and I can now debug this particular configuration of the Phone app on the Phone (but not on the emulators);

image

and that all works out fine with a slight change to the naming of the component that was being invokved in the default.js file. So, in terms of packaging;

  • A .NET “Universal WinRT Component” project produces one binary wrapped up in a .winmd file (with a .pri file and a .pdb if you build it and want it).
  • A C++ “Universal WinRT Component” project is going to produce 6 sets of outputs – you get Windows/Phone and then there’s variants of x86, x64 and ARM to think about although I’m not sure that you ever need to ship your x86/x64 binaries for the Phone unless you’re shipping them so that someone can use them in an emulator.

Naturally, that .NET component would change if it took a dependency on a C++ component.

Playing Around – The Names Remain the Same

I took the C++ code out of my project and reverted back to where the 2 JavaScript Windows/Phone projects are referencing the same, Universal, WinRT component implemented in .NET. I also reverted my project configuration back to “AnyCPU”.

image

Given the nature of JavaScript, the “binding” between the line of code that I’ve written to invoke the component;

                  var promise = PortableComponentCpp.Component.showAsync("Hello World");

                  promise.done();

and the actual invocation has to be pretty loose – i.e. I suspect that it’s possible to have this same piece of code execute on both Windows/Phone and yet produce different results.

I played around with that a little. The first step I took was to have;

  • The Windows project reference the WindowsOnlyComponent
  • The Phone project reference the PhoneOnlyComponent

as below;

image

but, while this is possible, it shows that I messed up with my naming because Visual Studio will complain if I try and build that setup above;

image

so I messed up by putting my Component into a namespace called PortableComponent and then trying to package that into a .winmd file called [Windows/Phone]OnlyComponent.

Mistake.

I can change that though such that the project called WindowsPhoneOnlyComponent actually builds out a .winmd file called PortableComponent.winmd and I can do the same for the WindowsOnlyComponent project. Sure, it’s confusing but it saves me having to start again and so I did just that;

image

You might notice that above I changed the Assembly name and the Default namespace. I was not expecting to change the Default namespace and yet I found that it seemed to have a direct relationship with the name of the .winmd file that Visual Studio was producing. I did the same for the PhoneOnlyComponent project;

image

and then the references that I’ve made from the Windows and Phone projects will work as below;

image

and this continues to run/work just fine on both Windows and Phone with that shared default.js file still executing this line of code;

                  var promise = PortableComponent.Component.showAsync("Hello World");

                  promise.done();

and it’s working fine but the two projects are referencing different components and the implementation is different on Windows versus Phone because of the way I’ve now set my references up. For instance, I could easily hack the 2 implementations of my WindowsOnlyComponent and my PhoneOnlyComponent – here’s the Windows one;

namespace PortableComponent
{
  using PortableLibrary;
  using System;
  using Windows.Foundation;
  using Windows.UI.Popups;

  // Sealed because this is WinRT.
  public sealed class Component
  {
    // IAsyncOperation because this is WinRT.
    public static IAsyncOperation<IUICommand> ShowAsync(string message)
    {
      message = "Windows" + message;

      // We call into the portable .NET library.
      return (PointlessPortableDialog.ShowAsync(message).AsAsyncOperation());
    }
  }
}

and here’s the phone one;

namespace PortableComponent
{
  using PortableLibrary;
  using System;
  using Windows.Foundation;
  using Windows.UI.Popups;

  // Sealed because this is WinRT.
  public sealed class Component
  {
    // IAsyncOperation because this is WinRT.
    public static IAsyncOperation<IUICommand> ShowAsync(string message)
    {
      message = "Phone" + message;

      // We call into the portable .NET library.
      return (PointlessPortableDialog.ShowAsync(message).AsAsyncOperation());
    }
  }
}

and so now that code in default.js which is shared across Windows/Phone seems to be calling the same method on the same component but it’s not – it’s calling down into 2 different components that are doing a slightly different thing before they, in turn, call down into a shared implementation in a .NET library.

I don’t think this is radically different from making a Universal .NET project and writing some code in the shared folder that calls some Foo.Bar() method and then writing 2 versions of Foo.Bar() in the same namespace, building them into 2 different libraries and making sure that the Windows/Phone projects reference their own implementation. The difference there as I see it is that the resolution would be done at compile time whereas here in JavaScript it’s done at runtime.


Posted Fri, May 30 2014 4:14 PM by mtaulty

Comments

VB6 Programmer wrote re: Windows/Phone 8.1: “More Universal” WinRT Components
on Fri, May 30 2014 5:46 PM

Now that VB6 is Microsoft's most popular programming language (Tiobe index, May 2014) you should updated VB6 to support Windows Phone 8.1 (and Windows RT if it is going to continue).

visualstudio.uservoice.com/.../3440221-bring-back-classic-visual-basic-an-improved-versi