Leandro Taset Leandro Taset - 28 days ago 11
C# Question

Windows 8 start screen tile, based on desktop shortcut

I have a currently working code (C#, but not important) that adds a tile to the Windows 8 start screen by means of creating a shortcut file [

] within special directories like
%APPDATA%\Microsoft\Windows\Start Menu\Programs
%LOCALAPPDATA%\Microsoft\Windows\Application Shortcuts
. I have searched for and found several useful tools like
and OblyTile, which have helped in clearing several aspects about the quirks involved. I have also found many articles and questions related to the topic, but none quite exactly addresses my specific needs.

I'm using
(COM interop) to create the shortcut and
(same object instance) to add some apparently required properties to the link file. My specific problem and question are these:

The created tile works as expected in almost every aspect. It runs the intended command, has the intended background and foreground colors, and displays the custom associated icon (
image 144x144). The problem is that, even though it has a custom label string embedded in the link file [
], it just displays the name of the physical file minus the extension. That's not so horrible, but I would prefer that Windows honored the embedded property over the file name.

What might be missing in the link file that causes such behavior and not the desired one?


By using
, I have come across several so called "property sets", which are just properties grouped by their
. I have special interest in the sets
(the latter contains the ubiquitous

Extra question: can you please point to any resource which documents any (or both) of these two property sets? I mean, what do each property mean and how are they interpreted by Windows. This might be even more helpful than the main question. No matter if it's official or unofficial.


by calling it with a command line is not an option, as per requirements. According to what I've observed, I might need to add a custom
file in the link's target file parent directory. It would be desirable to avoid that, if at all possible, because the format is not documented.

Sample code

class is a plain-old & boring wrapper around the
COM interfaces. It works just fine, I'm completely sure the problem is not there.

using System;
using System.IO;

namespace Shell32NET
public static class Win8Tiles
#region Fields

/// <summary>
/// b725f130-47ef-101a-a5f102608c9eebac
/// </summary>
static readonly Guid ItemTypeGroup = new Guid(
0xb725f130, 0x47ef, 0x101a, 0xa5, 0xf1, 0x02, 0x60, 0x8c, 0x9e, 0xeb, 0xac

/// <summary>
/// b725f130-47ef-101a-a5f102608c9eebac, 4
/// </summary>
static readonly PropertyKey SystemItemTypeText = new PropertyKey(ItemTypeGroup, 4);

/// <summary>
/// 86d40b4d-9069-443c-819a2a54090dccec
/// </summary>
static readonly Guid TilePropertiesGroup = new Guid(
0x86d40b4d, 0x9069, 0x443c, 0x81, 0x9a, 0x2a, 0x54, 0x09, 0x0d, 0xcc, 0xec

/// <summary>
/// 86d40b4d-9069-443c-819a2a54090dccec, 2
/// </summary>
static readonly PropertyKey TileSmallImageLocation = new PropertyKey(TilePropertiesGroup, 2);

/// <summary>
/// 86d40b4d-9069-443c-819a2a54090dccec, 4
/// </summary>
static readonly PropertyKey TileBackgroundColor = new PropertyKey(TilePropertiesGroup, 4);

/// <summary>
/// 86d40b4d-9069-443c-819a2a54090dccec, 5
/// </summary>
static readonly PropertyKey TileForegroundColor = new PropertyKey(TilePropertiesGroup, 5);

/// <summary>
/// 86d40b4d-9069-443c-819a2a54090dccec, 11
/// </summary>
static readonly PropertyKey TileDisplayName = new PropertyKey(TilePropertiesGroup, 11);

/// <summary>
/// 86d40b4d-9069-443c-819a2a54090dccec, 12
/// </summary>
static readonly PropertyKey TileImageLocation = new PropertyKey(TilePropertiesGroup, 12);

/// <summary>
/// 86d40b4d-9069-443c-819a2a54090dccec, 14
/// </summary>
static readonly PropertyKey TileUnknownFlags = new PropertyKey(TilePropertiesGroup, 14);

/// <summary>
/// 9f4c2855-9f79-4b39-a8d0e1d42de1d5f3
/// </summary>
public static readonly Guid MetadataGroup = new Guid(
0x9f4c2855, 0x9f79, 0x4b39, 0xa8, 0xd0, 0xe1, 0xd4, 0x2d, 0xe1, 0xd5, 0xf3

/// <summary>
/// 9f4c2855-9f79-4b39-a8d0e1d42de1d5f3, 5
/// </summary>
public static readonly PropertyKey AppUserModelID = new PropertyKey(MetadataGroup, 5);

/// <summary>
/// b6578b39-11f9-449b-8438cb5cf03b7d9c
/// </summary>
static readonly Guid UnknownGroup1 = new Guid(
0xb6578b39, 0x11f9, 0x449b, 0x84, 0x38, 0xcb, 0x5c, 0xf0, 0x3b, 0x7d, 0x9c


/// <summary>
/// Creates a tile in the Windows 8 start screen.
/// </summary>
/// <param name="target">The file to be executed when the tile is clicked.</param>
/// <param name="appId">The registering application's ID.</param>
/// <param name="title">The caption text for the tile.</param>
/// <param name="imageFilename">The image to be shown in the tile.</param>
/// <param name="background">Background color for the tile.<para>
/// Must be in the hex ARGB form: 0xAARRGGBB.
/// Where AA is the alpha channel value, RR is for red, GG for green and BB for blue.
/// </para></param>
/// <param name="foreground">Foregreound color for the tile, in the
/// same format as <paramref name="background"/>.</param>
public static void CreateTile(
string target,
string appId,
string title,
string imageFilename,
uint background,
uint foreground
string appdata = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData);
if (appdata == null)
throw new NotSupportedException("The user's roaming application data directory does not exist.");

using (var link = new ShellLink())
link.TargetPath = target;

// The .lnk icon location and index (not quite important). Just using some defaults.
link.SetIconLocation(@"%SystemRoot%\System32\SHELL32.DLL", 135);

link.SetProperty(AppUserModelID, appId);

// Apparently required properties (AS-IS).
link.SetProperty(new PropertyKey(MetadataGroup, 11), true);
link.SetProperty(new PropertyKey(MetadataGroup, 19), "Microsoft.InternetExplorer.Default");
new PropertyKey(MetadataGroup, 20),
"-contentTile -formatVersion 0x00000002 -securityFlags 0x00000000 -url 0x00000057"

* These are not really working at the moment; the tile just shows the name of the .lnk file.
link.SetProperty(SystemItemTypeText, title);
link.SetProperty(TileDisplayName, title);

// Background and foreground.
link.SetProperty(TileBackgroundColor, background);
link.SetProperty(TileForegroundColor, foreground);

// Small and normal tile icon. Set your own.
string fileUri = new Uri(imageFilename).AbsoluteUri;
link.SetProperty(TileImageLocation, fileUri);
link.SetProperty(TileSmallImageLocation, fileUri);

// Apparently required, not the tiniest clue of why.
link.SetProperty(TileUnknownFlags, 0x41u);
link.SetProperty(new PropertyKey(UnknownGroup1, 4), 0x41u);

// The file should be saved to %LOCALAPPDATA%\Microsoft\Windows\Application Shortcuts
string filename = Path.Combine(appdata, @"Microsoft\Windows\Application Shortcuts");
filename = Path.Combine(filename, "Win8Tiles-Test");

filename = Path.Combine(filename, title + ".lnk");

function GetPropertyKeyCanonicalName(const AKey: TPropertyKey): UnicodeString;
  PropertySystem: IPropertySystem;
  PropertyDescription: IPropertyDescription;
  N: PWideChar;
  Result := '';
  if Succeeded(CoCreateInstance(CLSID_IPropertySystem, nil, CLSCTX_INPROC_SERVER, IPropertySystem, PropertySystem)) then
      if Succeeded(PropertySystem.GetPropertyDescription(AKey, IPropertyDescription, PropertyDescription)) then
          if Succeeded(PropertyDescription.GetCanonicalName(N)) then
              Result := N
          PropertyDescription := nil;
      PropertySystem := nil;