Blog ⋅ Peter Nelson

To make a Metro Appx Package from scratch, you must first …

by peterdn 18. September 2011 12:42

Windows 8 has been big news this week following its announcement and preview at the Microsoft BUILD conference.  After a bit of playing around with Visual Studio on the developer preview, I’ve become very intrigued with the new Metro platform and WinRT APIs.  Running through a few of the tutorials and samples, it looks very different to traditional Windows programming, and on the whole, quite promising and refreshing.

If you’re anything like me, you’ll be wanting to know what goes on beneath the surface when Visual Studio performs the incantations that result in your code coming to life.  So, I decided to write and package up a Metro app (almost) by hand, to see for myself exactly what is involved, and hopefully learn a thing or two about the new platform and tools.

Requirements


  1. The Windows 8 developer preview (with developer tools).
  2. A vague awareness of what Metro and WinRT are (see links at the end of this post if you’ve no idea what I’m talking about).
  3. Familiarity with digital certificates and Visual Studio command-line tools OR enough trust in me to blindly run commands I tell you to.
  4. A desire to learn about the processes involved in packaging and deploying Metro apps.

Overview

An overview of the process pipeline we will be following is shown below.  If you have experience working with Visual Studio command-line tools, several of these stages may already be familiar to you.

Process Pipeline

All code and resources used henceforth can be downloaded here or from the link at the end of the post.

The Code

Lets begin by writing a very simple Metro-style app that contains a Grid control and a Button that does nothing.  To simplify things at the command-line, these UI elements are created procedurally, rather than being defined in XAML markup, and the following code is all contained in the one file (MyApp.cs).  If you’re familiar with WPF (or indeed not) it should be reasonably obvious what is going on here:

using System;
using Windows.ApplicationModel.Activation;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Media;

namespace MyApp
{
    class Program
    {
        public static void Main (string[] args)
        {
            var app = new MyApp();
            app.Run();
        }
    }
    
    class MyApp : Windows.UI.Xaml.Application
    {
        public MyApp()
        {
        }
        
        protected override void OnLaunched(LaunchActivatedEventArgs args)
        {
            var layoutRoot = new Grid() { Background = new SolidColorBrush(Colors.Blue) };
            layoutRoot.Children.Add(new Button() { Content = "Hello!" });

            Window.Current.Content = layoutRoot;
            Window.Current.Activate();
        }
    }
}

Appx Manifest

Next, we write up the application manifest.  AppxManifest.xml contains metadata about the package and the application contained in it.  This includes information such as the app’s entry point, it’s capabilities (similar to Android permissions), and dependencies.  If you have already created a Metro app using Visual Studio, you may have noticed that a file named “Package.appxmanifest” is among those automatically generated for you.  Behind the scenes, when you hit build, Visual Studio chews up this file and spits out an AppxManifest.xml.  Let’s not worry about what black magic goes on there and just manually create our own:

<?xml version="1.0" encoding="utf-8"?>
<Package xmlns="http://schemas.microsoft.com/appx/2010/manifest">
  <Identity Name="MyApp"
            Publisher="CN=peterdn.com"
            Version="1.0.0.0" />
  <Properties>
    <DisplayName>MyApp</DisplayName>
    <PublisherDisplayName>peterdn.com</PublisherDisplayName>
    <Logo>Images\Logo.png</Logo>
    <Description>My Cool App</Description>
  </Properties>
  <Prerequisites>
    <OSMinVersion>6.2</OSMinVersion>
    <OSMaxVersionTested>6.2</OSMaxVersionTested>
  </Prerequisites>
  <Resources>
    <Resource Language="en-us" />
  </Resources>
  <Applications>
    <Application Id="MyAppId" 
        Executable="MyApp.exe" 
        EntryPoint="MyApp.App">
        <VisualElements 
            DisplayName="MyApp"
            Logo="Images\Logo.png"
            SmallLogo="Images\SmallLogo.png"
            Description="My Cool App"
            ForegroundText="light"
            BackgroundColor="#222222">
            <SplashScreen Image="Images\SplashScreen.png" />
        </VisualElements>
    </Application>
  </Applications>
</Package>

Most of this is pretty self-explanatory.  However, you should change the Name and Publisher attributes in the <Identity> tag to your own values.  As far as I can tell, Name can be anything you want (I chose a GUID because that’s what Visual Studio does).  However, Publisher must be the name of the root certificate that you will generate later.  If these do not correspond, you will not be able to sign the app.  Choose something sensible for the moment, such as “CN=my.domain.com”.

Also, if you changed the class or namespace names in the C# source above, don’t forget to update the EntryPoint attribute in <Application>.

Compiling

The basic operation of the C# compiler has not changed much in this new release, however there are a couple of interesting things that you should be aware of when developing a Metro app.  Firstly, a new build target has been introduced – /target:appcontainerexe.  Specifying this target informs the C# compiler to generate an executable that runs in the context of an AppContainer (i.e. the Metro UI ‘shell’).  Secondly, WinRT APIs are accessed through referencing .winmd metadata files.  These have the same format as .NET assemblies, and can therefore be viewed in your favourite reflector tool or disassembler.  On my install, these are located in the “C:\Program Files (x86)\Windows Kits\8.0\Windows Metadata” directory.  With a quick peek at the #using directives in the code above, and some trial and error with csc.exe, we can quickly work out the required references.  So, conjure up a Visual Studio 11 command prompt and run the following (superfluous newlines inserted for dramatic effect):

csc.exe /target:appcontainerexe 
        /out:MyApp.exe 
        /r:"C:\Program Files (x86)\Windows Kits\8.0\Windows Metadata\windows.applicationmodel.activation.winmd" 
        /r:"C:\Program Files (x86)\Windows Kits\8.0\Windows Metadata\windows.ui.xaml.winmd" 
        /r:"C:\Program Files (x86)\Windows Kits\8.0\Windows Metadata\windows.ui.xaml.media.winmd" 
        /r:"C:\Program Files (x86)\Windows Kits\8.0\Windows Metadata\windows.ui.xaml.controls.winmd" 
        /r:"C:\Program Files (x86)\Windows Kits\8.0\Windows Metadata\windows.ui.xaml.controls.primitives.winmd" 
        MyApp.cs

Packaging

Next, we build a simple directory structure for the package.  Create a new directory and copy MyApp.exe and AppxManifest.xml to its root.  Either create your own Logo.png, SmallLogo.png, and SplashScreen.png image resources (as specified in AppxManifest.xml), or use mine.  Place these images in an “Images” subdirectory.  Your structure should look something like this:

  • AppxManifest.xml
  • MyApp.exe
  • Images/
    • Logo.png
    • SmallLogo.png
    • SplashScreen.png

Now we pack up the directory into .appx form.  This is actually just standard ZIP format, however we will prefer to use the new MakeAppx.exe tool (rather than WinZip) to create and unpack packages.  Hit the command prompt again and run:

MakeAppx.exe pack /d .\output /p MyApp.appx

If your AppxManifest.xml has any glaring problems, they should be detected at this stage.  Pay attention to any error messages and double check your copypasta.

WARNING: By default, everything in the “output” directory will be added to the package.  Make sure that it only contains files you want to distribute.

Signing

Signing is a crucial stage of the process. The Metro environment in Windows 8 is much more strict and security-conscious than the desktop environment. Every application must be signed by a trusted entity before the system will allow it to be installed. Presumably, this will be done by Visual Studio when you deploy a package for release and upload it to the Windows App Store. Even during testing, Visual Studio creates temporary certificates for your apps that allow them to run on your development machine.  If we are to do this without the aid of Visual Studio, we first need to create a trusted root certificate, then sign the package using a client certificate.

Generating a Trusted Certificate

To the command prompt!

makecert.exe -n "CN=peterdn.com" -r -a sha1 -sv peterdn.com.pvk peterdn.com.cer –ss root

If you haven’t a clue what’s going on here, simply understand that this generates the public and private key components of a root certificate, and stores them in the files “peterdn.com.cer” and “peterdn.com.pvk”, respectively.  The filenames you choose don’t really matter, but you are probably best naming them after your own domain.  What is important is the certificate name, specified here in the parameter “CN=peterdn.com”.  Change this to your domain, but also remember to mirror the change in the <Identity> element of your AppxManifest.xml, as mentioned previously.  Repackage if necessary.

IMPORTANT: The above command installs the certificate into Windows’ trusted root store, meaning Windows will implicitly trust anything that is signed by it.  This obviously poses a huge security risk.  It is highly recommended that you keep the private key file (.pvk) in a very safe place, and remove the certificate from your root store when you are finished with it.  This can be done from the command-line with certutil.exe, or via GUI with certmgr.exe (where the certificate will be listed under the “Trusted Root Certification Authorities” tab).

Now we generate a client certificate that we use to sign the package.  This certificate is in turn signed by the root certificate in order to establish the required chain of trust.  Run the following command (again, substituting in your own domain name where appropriate):

makecert -a sha1 -sk "peterdn.com" -iv peterdn.com.pvk -n "CN=peterdn.com" -ic peterdn.com.cer -sr currentuser -ss My

This automatically installs the client certificate into your personal store.

Signing the Package

We need to obtain the thumbprint of the client certificate we just created.  Powershell niftily allows us to navigate and explore the certificate store from the command-line.  Run the following command and make a note of the appropriate thumbprint (mine shown below):

PS C:\> dir cert:\CurrentUser\My


    Directory: Microsoft.PowerShell.Security\Certificate::CurrentUser\My


Thumbprint                                Subject
----------                                -------
75DB2ACF57A1BC2DBBF239BBD0FB143F91771103  CN=peterdn.com

Now back to the command prompt.  Sign the package, substituting in your own certificate’s thumbprint:

signtool.exe sign /fd sha256 /sha1 0a241ba3a94080f0df32d90dc60358368a4ebce0 MyApp.appx

If you receive an error like “SignTool Error: An unexpected internal error has occurred. Error information: "Error: SignerSign() failed." (-2147024885/0x8007000b)”, you’ve probably not been consistent with your certificate names.  Double check these and try again.

Installing

To install the package, hop on back over to Powershell.  Execute the following cmdlet:

Add-AppxPackage .\MyApp.appx

If successful, the app should now appear somewhere on the start screen as shown:

App tile on start screen

Running the app, we see the gorgeous UI we expect:

Our Metro app UI

Deploying

The ‘encouraged’ way to deploy Metro apps is obviously via the Windows App Store, and the developer preview of Visual Studio includes relevant tools for validating and uploading apps.  However, at the time of writing, the App Store has not yet been enabled and information about it is still scarce.

So how are you going to deploy your awesome in-house Metro app to your hundreds and thousands of corporate employees?  Well, pretty much the way you deployed it on your own machine.  Install your root certificate (in my case, this was the file “peterdn.com.cer”) on the target machines either using the certmgr.exe GUI or by running the command:

certutil.exe -addstore root peterdn.com.cer

Also, please please remember the above disclaimer about the security implications of abusing trusted root certificates.

Your package can then be installed using Powershell as above.

Download


  1. Code and resources

Relevant Links

How to: Install, validate, and upload your package – MSDN article which provides more details.
Lap around the Windows Runtime – Great session from BUILD giving an overview of WinRT.
Windows Runtime API reference – MSDN reference for the WinRT API.
Windows Runtime internals: understanding "Hello World" – Another highly recommended session from BUILD giving a behind-the-scenes look at how WinRT and app installation works.
How to create a package manifest manually – MSDN reference for more details about the appx manifest.
Introduction to code signing – MSDN introduction to digital certificates and signing.

Tags: , ,

Windows 8 | WinRT

Add comment