Microsoft Longhorn

APIs Hacking Avalon #3: Compiling XAML

In this third part of the Hacking Avalon series, we are taking a closer look at the process of making an Avalon application. To do this, we will be using a special tool only available in early Longhorn builds. This tool is called the Avalon Compiler or simply ac. This tool does what its name suggests; compile Avalon. What is that precisely?

Just a quick note before we begin; this post is completely based on the Avalon version included with 3683. Though many of the concepts explained here hold for later builds too, some may not be applicable to later versions of Avalon.

The basics of XAML

Avalon introduces a mark-up language called eXtensible Application Mark-up Language or XAML for short (pronounced zaml). Using XAML, it’s easy to quickly create a complete user interface. XAML is a dialect of XML and therefore easy to learn for developers already familiar with HTML or XML. Each element in the mark-up corresponds with an Avalon object in the .NET runtime, and each attribute of an element corresponds to a property of that object. Here is a sample of some mark-up:

<FlowPanel xmlns="using:System;System.Windows;System.Windows.Controls" Background="LightBlue">
  <Button Height="100px">Clicky</Button>
  <TextPanel Foreground="White" FontFamily="Trebuchet MS" FontSize="72pt">Hello, world!</TextPanel>
</FlowPanel>

Saving this as a file with the xaml extension will create an executable “Avalon Application”. The built-in Avalon Shell Handler can load the file directly and will happily draw the interface defined in the mark-up. It will do so in an Internet Explorer window. The example mark-up above will yield the following result:

Example XAML rendered in Longhorn Internet Explorer

Note that, we used nothing but mark-up to define this little “program”. We even defined a button. At the moment, nothing happens when the button is clicked. This is of course all good and well, but what if we want our users to be able to interact with the interface? The next thing we will do is to add a click event to the button.

Adding code

To add event handlers to your interface you need to supply some extra information in the mark-up. First, we add an extra XML namespace “Definition” and declare the language we are planning on using (C#). Next, all you need to do is to add the corresponding triggers to your mark-up and create a Code element to hold your code. Code is wrapped in a character data (CDATA) section so that it will not be interpreted by the XAML parser. Here is the mark-up with a button click handler added.

<FlowPanel xmlns="using:System;System.Windows;System.Windows.Controls" xmlns:def="Definition" def:Language="C#" Background="LightBlue">
  <Button Height="100px" Click="handleClick">Clicky</Button>
  <TextPanel Foreground="White" FontFamily="Trebuchet MS" FontSize="72pt" ID="TextArea">Hello, world!</TextPanel>
  <def:Code>
  <![CDATA[
    void handleClick(Element el, ClickEventArgs args) {
      TextArea.Nodes.Add("Button clicked");
    }
  ]]>
  </def:Code>
</FlowPanel>

Even though the above mark-up is valid, running the file directly through the Avalon Shell Handler will result in an exception being thrown by Avalon’s XAML parser: “To use event handlers you will need to compile your xaml file using ac”. This is where the Avalon Compiler comes into play.

Error attempting to include events within XAML

Compiling mark-up

The Avalon Compiler is a powerful tool that let’s compile mark-up to code, or a binary formatted variant of XAML, better known as BAML. Using the compiler from the command line is quite simple. From a command prompt window, perform these tasks:

  • browse to C:\Windows\Microsoft.NET\Avalon\
  • execute ac [path to xaml file] -out:[output directory]

An example ac session, compiling the example.xaml file.

Running the Avalon Compiler

The compiler will output a couple of different files by default:

  • exampleApp.exe: A secure stub executor, nicknamed themepark. This is an unmanaged Avalon application bootstrapper which can start the application safely.

  • example.baml: A binary serialized version of your original mark-up.

  • exampleApp.dll: Application initializer providing a “SecureEntry”.

  • example.dll: Contains a partial version of the FlowPanel element including the button’s event handler along with some helper functions.

Alternatively, using one of the different switches ac supports, it’s possible to generate debug or “full code” binaries. Full code compilation will omit creation of a baml file and instead compiles all mark-up to code (a variant known as CAML) in a single dll. You can download the example files and the binaries here.

Example mark-up files and binaries

The final result

Executing the exampleApp executable will open your Avalon application in a dedicated window. All event handlers are now properly working as expected.

The event handler now works after compilation with the Avalon Compiler

As expected, the event handler for the button now works. A click on the button will add the text 'Button click' to the text area.

We have now created our own simple Avalon application! The Avalon Compiler can also build more advanced applications. Complete Avalon projects can be created and compiled using Longhorn Project files.

Later builds

When some people found the Avalon Compiler executable still lingering in later builds (such as 4051), they started using this to compile their XAML to BAML. By that time a major rearchitecturing had taken place, AC was long deprecated. Microsoft employee Rob Relyea told them to use the new compiler XamlC instead which is included in the Longhorn SDK given out at PDC 2003. As part of these changes, the CAML option, where a XAML file is compiled into raw IL instructions which build the user interface, was dropped.