2 Jan

Retrieving Windows 8 Theme Colours

See also: Windows 8 Theme Colours Reference.

Windows 8 doesn’t offer developers access to system theme colours, unlike its cousin, Windows Phone. Even for a version 1 product, this seems like a strange omission. Then again, we still don’t have a working public API for retrieving the Aero glass colour (or whatever we call it now that Aero’s gone) 6 years after the release of Windows Vista.

The functions that the system uses to retrieve colours are defined in UxTheme.dll. In particular, we’re interested in GetImmersiveColorSetCount (export #94), GetImmersiveColorFromColorSetEx (export #95), GetImmersiveColorTypeFromName (export #96), GetImmersiveUserColorSetPreference (export #98) and GetImmersiveColorNamedTypeByIndex (export #100). Relying on undocumented functions is a bad idea, and will cause your program to fail certification, so you won’t be able to use them in apps distributed through the Windows Store anyway.

For desktop developers who still want to use these functions, read on. Just assume that they’ll break in future versions of Windows (or even with patches to Windows 8).

Screenshot of Windows 8 Colours

There are 25 colour sets available in Windows 8, pictured above. Users can switch between these in the Metro control panel (under Personalise > Start screen). Additionally, when a high contrast theme is enabled, colours in the start screen are based on traditional window element colours, retrieved with the GetSysColor function. With the four high contrast themes included in Windows 8, this means there are effectively 29 different colour sets for a standard setup. Use the GetImmersiveColorSetCount function to retrieve the number of colour sets available and the GetImmersiveUserColorSetPreference function to retrieve the ID of the active colour set. The ID is also stored in the registry key HKCU\Software\Microsoft\Windows\CurrentVersion\Explorer\Accent with the name ColorSet_Version3. It occurred to me that one could hard-code values from the 25 colour schemes and read this registry value, but Metro-style apps aren’t even allowed to access the registry – so much for that idea.

The GetImmersiveUserColorSetPreference functions takes two boolean parameters. The first should be set to true to force UxTheme to read the value stored in the registry (and update the system setting if what’s in the registry is different to what’s in memory). To be honest, I’m not entirely sure what the second parameter does – setting it to true will stop the function attempting to retrieve the user preference a second time if the first call returns –1. I think this is only relevant in the event that UxTheme doesn’t have permission to update the system setting with the value from the registry. In any case, you should be able to disregard these parameters in most scenarios (set them both to false).

Screenshot of Windows 8 Personalisation Settings

The GetImmersiveColorNamedTypeByIndex function returns a (pointer to a) string containing the name of an element like ‘StartBackground’ or ‘StartDesktopTilesBackground’. There are 767 (0x2ff) names in total – unfortunately there seems to be no function to retrieve this number. To get the colour type (ID) from a name, we use the GetImmersiveColorTypeFromName function. We must prepend ‘Immersive’ to the string first, however, or the function will fail (‘StartBackground’ becomes ‘ImmersiveStartBackground’, for example). (In fact, any 9 characters at the start will do – ‘xxxxxxxxxStartBackground’ will work just as well.)

GetImmersiveColorTypeFromName returns a number between 0 and 766 (0x2fe). Only the first 108 types (0 to 107) correspond to colours that change according to the colour set – the remaining 659 are static (unless high contrast mode is enabled).

GetImmersiveColorFromColorSetEx takes four parameters. The first is the colour set ID (between 0 and 24 for Windows 8) and the second is the colour type (e.g. 0 for ‘StartBackground’). If the third parameter determines whether high contrast mode should be ignored – set it to 1 to retrieve the active colour set’s colours even when high contrast mode is enabled. The fourth parameter can be set to 1 to force UxTheme to check whether the system is in high contrast mode even with it already thinks it is (this check would otherwise only occur if high contrast mode had previously not been enabled).

Detecting User Preference Updates

Listen for WM_SETTINGCHANGE to detect when the user changes the colour scheme. lParam will point to a string with the value ‘ImmersiveColorSet’. When high contrast mode is enabled or disabled, lParam will point to a string with the value ‘WindowsThemeElement’.

P/Invoke Signatures

These P/Invoke signatures should be of help to C# developers wishing to use these functions in desktop programs (again, assume they could stop working at any time):

[DllImport("uxtheme.dll", EntryPoint = "#94")]
public static extern int GetImmersiveColorSetCount();
/// <summary>
/// Retrieves an immersive colour from the specified colour set.
/// </summary>
/// <param name="dwImmersiveColorSet">Colour set index. Use <see cref="GetImmersiveColorSetCount"/> to get the number of colour sets available.</param>
/// <param name="dwImmersiveColorType">The colour type. Use <see cref="GetImmersiveColorTypeFromName"/> to get the type from an element name.</param>
/// <param name="bIgnoreHighContrast">Set this to true to return colours from the current colour set, even if a high contrast theme is being used.</param>
/// <param name="dwHighContrastCacheMode">Set this to 1 to force UxTheme to check whether high contrast mode is enabled. If this is set to 0, UxTheme will only perform this check if high contrast mode is currently disabled.</param>
/// <returns>Returns a colour (0xAABBGGRR).</returns>
[DllImport("uxtheme.dll", EntryPoint = "#95")]
public static extern uint GetImmersiveColorFromColorSetEx(uint dwImmersiveColorSet, uint dwImmersiveColorType, bool bIgnoreHighContrast, uint dwHighContrastCacheMode);
/// <summary>
/// Retrieves an immersive colour type given its name.
/// </summary>
/// <param name="pName">Pointer to a string containing the name preprended with 9 characters (e.g. "Immersive" + name).</param>
/// <returns>Colour type.</returns>
[DllImport("uxtheme.dll", EntryPoint = "#96")]
public static extern uint GetImmersiveColorTypeFromName(IntPtr pName);
/// <summary>
/// Gets the user's colour set preference (or default colour set if the user isn't allowed to modify this setting according to group policy).
/// </summary>
/// <param name="bForceCheckRegistry">Forces update from registry (HKCU\Software\Microsoft\Windows\CurrentVersion\Explorer\Accent\ColorSet_Version3).</param>
/// <param name="bSkipCheckOnFail">Skip second check if first result is -1.</param>
/// <returns>User colour set preference.</returns>
[DllImport("uxtheme.dll", EntryPoint = "#98")]
public static extern int GetImmersiveUserColorSetPreference(bool bForceCheckRegistry, bool bSkipCheckOnFail);
/// <summary>
/// Retrieves names of colour types by index.
/// </summary>
/// <param name="dwIndex">Colour type index (0 to 766/0x2fe).</param>
/// <returns>Pointer to a string containing the colour type's name.</returns>
[DllImport("uxtheme.dll", EntryPoint = "#100")]
public static extern IntPtr GetImmersiveColorNamedTypeByIndex(uint dwIndex);

Sample Code (C#)

The following code retrieves the ‘StartSelectionBackground’ colour from the active colour set (assuming the above P/Invoke signatures).

int colourset = Colour.GetImmersiveUserColorSetPreference(false, false);
IntPtr pElementName = Marshal.StringToHGlobalUni("ImmersiveStartSelectionBackground");
uint type = Colour.GetImmersiveColorTypeFromName(pElementName);
Marshal.FreeCoTaskMem(pElementName);
uint colourdword = Colour.GetImmersiveColorFromColorSetEx((uint)colourset, type, false, 0);
byte[] colourbytes = new byte[4];
colourbytes[0] = (byte)((0xFF000000 & colourdword) >> 24); // A
colourbytes[1] = (byte)((0x00FF0000 & colourdword) >> 16); // B
colourbytes[2] = (byte)((0x0000FF00 & colourdword) >> 8); // G
colourbytes[3] = (byte)(0x000000FF & colourdword); // R
Color colour = Color.FromArgb(colourbytes[0], colourbytes[3], colourbytes[2], colourbytes[1]);

6 thoughts on “Retrieving Windows 8 Theme Colours

  1. Hi Quppa, interesting article, is it possible to know the other hidden entrypoint functions in the uxtheme.dll? i noticed that the functions you refer are all hidden, suppose they are private. Wondering the method you used to extract the functions even if hidden. Can you share it? Im looking for set functions, instead of get.

    Thank you,

    • I recommend the powerful debugger IDA. It can connect to the Microsoft symbol server to get the names of private functions like those mentioned in this post.

      Export #97 is SetImmersiveUserColorSetPreference(uint, bool). I’m not sure what the second argument does (you’ll have to go through the disassembled code in IDA), but I’m guessing the first argument is the colour set number (0 to 24). The actual colours for each set are hard-coded in uxtheme.dll and none of the functions in the library will help you modify them. I think Stardock’s Decor8 patches the actual DLL, but I’m not certain.

      These functions are very likely changing in Windows 8.1 – in early builds, colour sets are gone and users can set arbitrary accent and background colours.

      • Very nice, i just downloadaded the IDA tool, but i find a little hard to work with it, opened the uxtheme.dll but dont know how to work with the IDA Tool to find the private functions. Do you know if the SetImmersiveUserColorSetPreference(uint, bool) also applies the color without need to sign out?

      • I confirmed, it works perfectly, but the Accent theme must be another function, do you know wish is?

        Thank you

  2. Ok, i discovered for the accent theme you only need to change reg key: HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer\Accent\AccentId_v8.00, and the theme is applied immediately

    But im sure there is some set function to do it, without registry hack.

    • I’m not sure about functions for getting or setting the accent image, actually. They might not be in UxTheme.dll.

      There are no good options here, but relying on an undocumented registry key is no worse than relying on an undocumented function. If setting the registry value works, I’d just use that method. Incidentally, the value in Windows 8.1 is called ‘MotionAccentId_v1.00′ (last I checked, which was a few leaked builds ago).

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>