Получение иконки, ассоциированной с некоторым типом файла

Три часа утра, разгребаю почту скопившуюся за день и натыкаюсь на письмо с вопросом о том, как получить иконку для файла с определенным расширением. Первой мыслью было - сказать о WinAPI функции ExtractIcon и пойти спать, но почему-то эта мысль не победила желание написать пару строк кода.

Я быстренько накидал вот такой прототип:

image  (использую Zoom для растягивания элемента в Picture).

Для этого интерфейса создаю коллекцию объектов FileIcon описанных ниже  и привязываю к форме:

private void FormMain_Load(object sender, EventArgs e)
{
    FileIcons.FileIconCollection col = FileIconCollection.GetSystemFileIcons();
    extCombo.DataSource = col.FileIcons;

}

private void extCombo_SelectedIndexChanged(object sender, EventArgs e)
{
    extPicture.Image = ((FileIcon)extCombo.SelectedItem).Icon.ToBitmap();
}

Сами объекты:

public class FileIcon
{
    public Icon Icon { get; set;}
    public string FileExtension { get; set;}

    public override string ToString()
    {
        return FileExtension;
    }
}

Самое интересное - как получить коллекцию. На самом деле это очень просто - вся информация о привязаных к определенному расширению файла иконках храниться в реестре в ветке HKEY_CLASSES_ROOT, вот оттуда их можно и вытащить, а с помощью ExtractIcon получить саму иконку. Код очень простой:

public class FileIconCollection
{

    // WinAPI function
    [DllImport("shell32.dll", EntryPoint = "ExtractIconA", CharSet = CharSet.Ansi, SetLastError = true, ExactSpelling = true)]
    private static extern IntPtr ExtractIcon(int hInst, string lpszExeFileName, int nIconIndex);

    public List<FileIcon> FileIcons { get; private set; }

    private FileIconCollection() { }

    private static Icon GetIcon(string iconPath)
    {
        int strIndex = iconPath.IndexOf(",");
        string iconFileName = (strIndex > 0) ? iconPath.Substring(0, strIndex) : iconPath;
        int iconFileIndex;

        int.TryParse(iconPath.Substring(strIndex + 1), out iconFileIndex);

        // Grab icon handle
        IntPtr hIcon = ExtractIcon(0, iconFileName, iconFileIndex);

        return (hIcon != IntPtr.Zero) ? Icon.FromHandle(hIcon) : null;

    }

    public static FileIconCollection GetSystemFileIcons()
    {

        List<FileIcon> list = new List<FileIcon>();

        RegistryKey extRoot = Registry.ClassesRoot;

        foreach (string key in extRoot.GetSubKeyNames())
        {
            // skip if it is non file extension  key
            if (String.IsNullOrEmpty(key) || (key.IndexOf(".") != 0)) continue;

            RegistryKey extKey = extRoot.OpenSubKey(key);

            // skip if no such element
            if ((extKey == null) || (extKey.GetValue("") == null)) continue;

            // get sub key
            string iconKey = String.Format("{0}\\DefaultIcon", extKey.GetValue(""));

            RegistryKey extIcon = extRoot.OpenSubKey(iconKey);

            // skip if no such element
            if ((extIcon == null) || (extIcon.GetValue("") == null)) continue;

            FileIcon fi = new FileIcon { FileExtension = key, Icon = GetIcon(extIcon.GetValue("").ToString()) };
            extIcon.Close();
            list.Add(fi);
        }

        extRoot.Close();

        return new FileIconCollection { FileIcons = list };
    }
}

Надеюсь, что несмотря на позднее время (или очень раннее) код понятен. Прицепил исходный код в виде solution для VS2008.

FileIconsDemo.zip