404
+Page not found
+diff --git a/.nojekyll b/.nojekyll new file mode 100644 index 0000000..e69de29 diff --git a/404.html b/404.html new file mode 100644 index 0000000..a20edb7 --- /dev/null +++ b/404.html @@ -0,0 +1,171 @@ + + +
+ + + + + + + +Page not found
+Compiled UIX (often shortened to "UIB" for "UI Binary") is one of two formats used by Iris 4 for defining user interfaces. UIB is generated by passing one or more UIX XML files to the UIX compiler. The UI definition is pre-processed into custom bytecode alongside a slew of data tables. Although UIB bytecode instructions are much higher level, interpreter is conceptually similar to emulating a CPU in that they are still relatively simple instructions which are interpreted in a fetch + decode + execute loop.
+Note that the format used by Iris 4 is significantly different than Iris 3's UIB, which can be identified with the file magic "UIX2008"
.
Nearly all of the markup-related code is in the Microsoft.Iris.Markup
namespace, including compiled UIX. Most of the functions responsible for loading compiled UIX files is in Microsoft.Iris.Markup.CompiledMarkupLoader
, with some key functionality being delegated to other classes. Most notably, the bytecode interpreter is implemented in Microsoft.Iris.Markup.Interpreter
.
Being a binary data format, UIB is capable of storing several primitive data types.
+All integers are stored in little endian, as is standard for Windows.
+All offsets are stored as unsigned 32-bit integers (UInt32
), relative to the start of the file unless otherwise specified.
Offset ranges are typically specified with an inclusive start offset and exclusive end offset: \([\mathrm{Start}, \mathrm{End})\).
+Strings are stored length-prefixed with a UInt16
preamble, followed by encoded characters. If the preamble is 0xFFFF
, the string is null. Otherwise, the most significant bit whether the characters are UTF-8 encoded, and the remaining 15 bits are the number of characters (not bytes) in the string.
Length value (binary) | +Meaning | +
---|---|
1111 1111 1111 1111 |
+Null string | +
1xxx xxxx xxxx xxxx |
+UTF-8 character encoding | +
0xxx xxxx xxxx xxxx |
+UTF-16 character encoding | +
Most strings are not stored inline, but instead as Int32
indexes into the Strings section of the Binary Data Table. This allows for common strings to be deduplicated, which can reduce file size.
String arrays are lists of string references. This means that they are effectively Int32
arrays, where each item is an index into the string portion of the Binary Data Table.
Arrays of 32-bit integers are also stored prefixed with their length, where, similarly to strings, a 'negative length' is interpreted as a null array. Otherwise, each integer is stored one after the other. Both signed and unsigned integers (UInt32
and Int32
) can be stored with in this format, but the Iris library always reads the values as unsigned, requiring callers to unchecked cast the value to Int32
for signed integers.
Boolean values are stored as a single byte, where 0
represents false
and 1
represents true
.
Enums are usually stored as 32-bit integers. Naturally, the meaning of a particular integer value depends which enum it is being interpreted as.
+MarkupType
Name | +Value | +
---|---|
None |
+0x00000000 |
+
UI |
+0x01000000 |
+
Class |
+0x02000000 |
+
Effect |
+0x03000000 |
+
DataType |
+0x04000000 |
+
DataQuery |
+0x05000000 |
+
A custom binary format is used to store all compiler output. This format is divided into several sections, and can even be split across multiple files using shared Data Tables.
+The first four bytes are always 0x5549421A
, which spell out "UIB␚"
in ASCII. The next four bytes contain some representation of the UIB version, although the exact format is unknown. All known Iris 4 releases, including 4.0 and 4.8 Beta, use 1012
(0x3F4
).
The Table of Contents begins at offset 0x0008
, with two offsets specifying the start and end of the object section. Locations 0x0010
and 0x0014
contain the start and end of the Line Number Table, respectively.
The last item stored in the Table of Contents is a reference to the Binary Data Table. This is composed of two fields, of which only one can be set at at time. The value at offset 0x0018
is the start of a string. If the string is not null, then it is used as the resource URI to load a shared Data Table from. If it is null, then the UInt32
at location 0x001A
is the offset to the Data Table embedded within the current file.
The Dependencies section is a list of UIX files to include, encoded as the unsigned 16-bit count followed by a series of entries. Each include is composed of a flag that stores whether the referenced file is UIX XML, and the reference's compiler name string. This name is almost always the URI the file was loaded from.
+As an example, a Dependencies section with two includes might be stored as shown below. Note that all offsets are relative to the first byte of the dependency count.
+Start offset | +Value | +Meaning | +
---|---|---|
0x00 |
+0x02000000 |
+The list contains 2 includes | +
0x04 |
+0x00000000 |
+dependencies[0] is compiled UIB |
+
0x05 |
+0x05000000 |
+The URI of the 1st dependency is the 6th string in the Data Table | +
0x09 |
+0x01 |
+dependencies[1] is UIX XML |
+
0x10 |
+0x02000000 |
+The URI of the 2nd dependency is the 3rd string in the Data Table | +
The Type Export Declarations are composed of two tables: the Export Table and Alias Table.
+The Export Table is a length-prefixed (UInt16
) list of exports, where each export is a type defined with a reference to the local name and the markup type.
The Alias Table allows a UIB file to export imported types under a different name. Each entry is exactly 20 (0x14
) bytes long and is composed of the desired alias, the dependency to load it from, and the name of the target type. Both the alias and target type name are stored a string references. The dependency is always referred to using an index, either into import table of the Shared Binary Data Table if one is specified, or the file's dependencies.
Offset into entry | +Meaning | +
---|---|
0x00 |
+String reference to the desired Alias | +
0x04 |
+UInt16 index into the Dependencies list |
+
The Binary Data Table consists of several subtables, with each one containing a different types of constant data. These subtables are stored in the following order:
+1. Strings
+1. ???
The Strings table is effectively a list of strings, though unlike the primitive string[]
, it is actually stored as char[][]
.
The first four bytes of the Strings table contain the length of the list as a 32-bit integer. Although this value cannot be negative, UIX.dll
ultimately uses this as an Int32
to allocate memory, so theoretically a maximum of 0x7FFFFFFF
or 2,147,483,647 strings can be stored in a single UIB file.
Following the string count is a series of offsets relative to the first entry in the offset table (the byte immediately after the string count bytes). This is used similarly to a jump table, where the first chunk of the table is an array of fixed-size offsets into the second chunk. When UIB file is being read from fixed memory, this allows Iris to jump directly to the requested string using its index without having to read the entire table or every string before it.
+As an example, a string table with three entries might be stored as shown below. Note that all offsets are relative to first entry in the jump table.
+Start offset | +Value | +Meaning | +
---|---|---|
-0x04 |
+0x03000000 |
+The table contains 3 strings | +
0x00 |
+0x0C000000 |
+strings[0] is located at offset 0x0C |
+
0x04 |
+0x1D000000 |
+strings[1] is located at offset 0x1D |
+
0x08 |
+0x23000000 |
+strings[2] is located at offset 0x23 |
+
0x0C |
+0x08000000 |
+strings[0] is 8 UTF-16 characters |
+
0x0D |
+"Γεια σας" |
+strings[0] character data |
+
0x1D |
+0x05800000 |
+strings[1] is 5 UTF-8 characters |
+
0x1E |
+"Howdy" |
+strings[1] character data |
+
0x23 |
+0x08800000 |
+strings[2] is 8 UTF-8 characters |
+
0x24 |
+"MOREtext" |
+strings[2] character data |
+
[Work in progress]
+Compiled UIX is loaded in N main passes, listed in order of execution below. "Depersist" usually refers to reading and processing encoded information, such as type exports.
+++Iris has two separate type systems-- the runtime types, which are your standard .NET types; and the markup type schemas, which of course are .NET types themselves, but are used to wrap runtime types for use by the UIX compiler and interpreter. Mapping from schema to runtime type and constructing instances from strings is easy enough, because those are both tasks the original UIX tooling has to do. Doing the reverse (finding the schema for a given runtime type, or encoding a runtime object into a string that can be parsed later) is much more difficult.
+
Microsoft Iris (sometimes called UIX) was a private UI framework for Windows. It was developed for internal use by various Microsoft Windows software, although only the Zune desktop software is known to use it.
+Unlike most modern UI frameworks, Iris does not provide default control styles-- library consumers are expected to define their own styles. However, some later versions of Iris included UIXControls.dll
, a resource library containing some limited styles for built-in controls. UI layouts are defined in XML-based .uix
files, which are nearly identical in structure to Media Center Markup Language (MCML). UIX versions 3.x and later compiled the XML-based layouts to a proprietary binary format that is interpreted at runtime by the UIX library.
Parts of the code suggest that Iris may have supported the Xbox 360 (referred to by its codename, Xenon). There is also evidence that a native (C++) version of the library was used by some in-box applications in Windows Phone 7.
+Zune software 2.0 introduced a new UI design, which later become the Metro design language. This was also the first version to utilize the then-new Iris framework. Iris's assembly version generally aligns with the Zune release it came with-- the first known release of Iris is 2.0 for this reason. Iris 2.0 also did not have the concept of "compiled UIX", so Zune 2.x releases contain readable UIX source code.
+The Zune desktop software is partially written in C#, namely ZuneShell.dll
. This library contains the entrypoint that Zune.exe
passes execution to. Along with the Iris startup code, it primarily contains code that glues some parts of the UI and the business logic together. However, note that the majority of logic was written as embedded UIX scripts in the various resource DLLs, which in early versions (2.x)
Despite being very powerful and flexible, especially compared to other UI frameworks of the time, Microsoft never released Iris for public use. Microsoft even added Microsoft.Iris.Application.VerifyTrustedEnvironment()
, which is called on startup in UIX applications to verify that the calling assembly is signed by Microsoft.
However, this check can be patched out with relative ease, though it should be done with caution. Distributing patched binaries violates U.S. copyright law and may land you in hot water.
+Microsoft Iris first appeared in the release of version 2.0 of the Zune desktop software. No pre-built controls were included at all, with even primitives like buttons requiring consumer to build from scratch. Compiled UIX also did not exist at this time. Instead, Iris would parse and interpret UIX XML at runtime. UIX XML syntax closely resembled US-20090327876-A1, a patent filed by Microsoft at the end of 2009, and Media Center Markup Language (MCML) as used by Windows Media Center.
+Iris 3.0 released with Zune 3.0 in late 2008. It was the most significant update to Iris as it introduced the UIX compiler. Rather than parsing XML at runtime, Iris could compile UIX files at buildtime into a proprietary format that resembled custom bytecode. The shipped version of UIX.dll
includes the original UIX XML interpreter and the binary UIX compiler, although neither are used by the Zune software at runtime. UIXC is an open-source command line program wrapping the UIX compiler.
Iris 4.0 was a minor update released with Zune 4.0 in 2009. By this time, UIX XML differed sightly from the source included in Zune 2.0. For example:
+HyperlinkRepeater.Source = [Text.Fragments];
to HyperlinkRepeater.Source = Text.Fragments;
if ([FragmentMouseFocus.Value])
to if (FragmentMouseFocus.Value)
<toptoolbar:TopToolbar Name="TopToolbar" Shell="{Shell}" FocusOrder="1">
+ <LayoutInput>
+ <DockLayoutInput Position="Top"/>
+ </LayoutInput>
+</toptoolbar:TopToolbar>
+
<toptoolbar:TopToolbar Name="TopToolbar" Shell="{Shell}" FocusOrder="1" LayoutInput="{DockLayoutInput.Top}"/>
+
Due to a lack of UIX XML source for recent versions, it is unclear if these changes were made in Iris 3.0, but they were definitely present by 4.0.
+Iris 4.0 also included UIXcontrols.dll
, a simple library containing some .NET code but mostly provided implementations of basic controls, such as buttons and scrollbars, and some higher level but still primitive building blocks.
Zune 4.8.2345.0 shipped the last known version of Iris, with the same assembly version as Zune.
+So I added an interface named
+IStringEncodable
that has what's essentially a specializedToString()
method. Each schema has a matching runtime type, and if the schema supports converting from a string, I modify the runtime class to implementIStringEncodable
and returns a valid string that UIX already knows how to parse.It's a pretty manual process, so I've been implementing that interface as I observe incorrect constants in the disassembly. Turns out the
+Image
schema supports string encoding, butUIImage
(the corresponding runtime class) didn't implementIStringEncodable
so it has the wrong representation in the disassembly.UIX has three different ways of "persisting" constants: string, binary, and canonical. Canonical here is basically like accessing a static property on a control type using the property name. Previously, I treated canonical constants the same as string constants, but I have a theory that the persist mode matters more than I thought. I suspect that's why I'm getting "index out of bounds" errors when trying to recompile UIXA files, because somewhere the markup system mistook a canonical mode as string mode and is looking in the wrong place.
+
Howdy, Argonauts! This site contains documentation about all things related to Zune.
+Warning
+These docs are a work in progress.
+