Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / desktop / Win32

OSIcon

4.84/5 (22 votes)
12 Jan 2010CPOL5 min read 69.1K   1.9K  
Library for handling and retrieving system icons

NOTE: If you are using Visual Studio use the Packet Manager NuGet to obtain the library: OSIcon

If you want to obtain the most recent source code, contribute, fork or open an issue, please go to github OSIcon project.

OSIcon/1.OSIcon_Explorer_MyComputer.png

OSIcon/2.OSIcon_Explorer.png

OSIcon/3.OSIcon_Explorer1.png

OSIcon/OSIcon_Explorer.png

OSIcon/OSIcon_Associations.png

OSIcon/OSIcon_Associations.png

OSIcon/OSIcon_IconExplorer.png

Table of Contents

Introduction

This library can retrieve icons from extensions and files, with additional information like file type (hard drive, folder, PHP Script File, ...). The library also provides a class for CACHE icons and creates an ImageList with the added icons.

Using the Code

Classes in the library

  • WinAPI namespace (Contains all Win API calls)
    • Shell32 static class (all API calls for Shell32.dll)
    • DwmApi static class (all API calls for Dmwapi.dll)
    • User32 static class (all API calls for User32.dll)
    • Comctl32 static class (all API calls for Comctl32.dll)
    • IShellFolder interface
  • <span style="color: rgb(153, 0, 0); font-family: Consolas, 'Courier New', Courier, mono; font-size: 14.6666669845581px;">Controls</span>

    • FileExplorer A control that behaves like Windows Explorer
  • Utilities static class (helper functions)
  • IconReader static class (read, handle icons)
  • IconManager class (IconReader wrapper with caching features, automatic creation of ImageList)
  • WindowsThumbnail class to retrieve Windows thumbnails on taskbar
  • About static class (stores some constants about the library, author, webpage, etc.)

Using the IconReader class

Get any icon from a file using "OSIcon.IconReader.ExtractIconFromFile(path, isLarge);".

C#
// To extract the file icon we simply can do:
// First param will be the path to file.
// Last param define icon size (true = Large, false = Small)
Icon icon = OSIcon.IconReader.ExtractIconFromFile("C:\\pathtofile.png", true);

Now, if you want to extract an icon from a resource file like shell32.dll, you can do: "OSIcon.IconReader.ExtractIconFromFile(path, iconIndex);".

C#
// 5, is the icon index
// http://cfs6.tistory.com/upload_control/download.blog?
// fhandle=YmxvZzEwMTUzNkBmczYudGlzdG9yeS5jb206L2F0dGFjaC8wLzAxMDAwMDAwMDAwMC5qcGc%3D
// 5 will return Open Folder image from shell32.dll
Icon icon = OSIcon.IconReader.ExtractIconFromFile("C:\\Windows\\system32\\shell32.dll", 5);

In Windows Explorer, FileZilla, etc., we can see the file type (Folder, PHP Script, Dynamic Link Library, etc.). To retrieve that information, we need to use some API calls. Using OSIcon, this is quite simple: "OSIcon.IconReader.GetFileIcon(pathOrExtension, IconReader.IconSize);".

C#
// NOTE: filename can be an partial extension (.png), or a full path ("C:\\file.png")
// IconInfo class store all information about the icon
IconInfo iconInfo = OSIcon.IconReader.GetFileIcon(".png", IconReader.IconSize.Large);
MessageBox.Show(string.Format("Display Name: {0}\nFile Type: {1}", 
                iconInfo.DisplayName, iconInfo.TypeName));

We can also retrieve file extensions from regedit and extract their icons, using: "OSIcon.IconReader.GetFileTypeAndIcon();".

C#
// Get all available extensions
// Dictionary Key = extension, value = path to icon
Dictionary<string, string> _iconList = _iconList = 
OSIcon.IconReader.GetFileTypeAndIcon();
// Foreach each extension
foreach (KeyValuePair<string, string> list in _iconList)
// Extract icon from file
Icon icon = OSIcon.IconReader.ExtractIconFromFile(_iconList[extension], 
                              isLarge ? true : false);

Getting all icons on a file is quite simple, using: "ExtractIconsFromFile(path, isLarge);".

C#
// From Sample Application see: "IconExplorer.cs" UserControl
filename = "C:\\Windows\\system32\\shell.dll";
Icon[] icons = IconReader.ExtractIconsFromFile(filename, true);
if(icons.Length == 0) return; // No icons found, return
// Loop through icons array
for (int i = 0; i < icons.Length; i++)
{
    // Do something here, im adding icon to an ImageList
    imageList.Images.Add(i.ToString(), icons[i]);
}

Using the IconManager class

Sometimes, we need to display our files and have 100s of files of the same type, e.g., .php; you can reuse icons obtained from the first PHP file in that case. (Please see FileExplorer control)

  • IconProperties class
    • IconsInfo (stores icons information and indexes) Dictionary<IconReader.IconSize, IconInfo>
C#
// If you want create a ImageList to store collected icons use true
// Small ImageList (true/false), Large ImageList (true/false)
// new OSIcon.IconManager() == new OSIcon.IconManager(true, true)
//
// Initalize Class, and create small, large, extralarge, jumbo
// Last param if set true, disable ExtraLarge or Jumbo if not supported by current OS
OSIcon.IconManager iconManager = new OSIcon.IconManager(true, true, true, true, true);
// Add some special icons to be used
// Add folder images
iconManager.AddFolder(); 
// Add Computer Drives (DVD Drive, Floppy, Hard Disk, etc.)
iconManager.AddComputerDrives(); 
 
// You also can add manualy, icons images to ImageList
// I use ":" because file path can't have ':' in name, so its a special mark
iconManager.ImageList[IconReader.IconSize.Small].Images.Add(
  ":Up-icon:", Properties.Resources.Up_icon16x16);
iconManager.ImageList[IconReader.IconSize.Large].Images.Add(
  ":Up-icon:", Properties.Resources.Up_icon32x32);
// ExtraLarge was introduced on XP so if you running XP
// or above add ExtraLarge capabilities
if (OSIcon.Utils.IsXpOrAbove())
{
    iconManager.ImageList[IconReader.IconSize.ExtraLarge].Images.Add(
                ":Up-icon:", Properties.Resources.Up_icon48x48);
}
// Jumbo was introduced on Vista so if you
// running Vista or above add Jumbo capabilities
if (OSIcon.Utils.IsVistaOrAbove())
{
    iconManager.ImageList[IconReader.IconSize.Jumbo].Images.Add(
          ":Up-icon:", Properties.Resources.Up_icon256x256);
}
// NOTE: iconManager.ImageList[IconReader.Size]
// can be assign in any control that uses ImageList

The class is initialized and ready to use; now, we create a function to show My Computer and the path contents:

C#
void ShowMyComputer()
{
    // List all drives on computer
    foreach (string drive in Directory.GetLogicalDrives())
    {
        // Always when you add a icon to list it will return IconProperties 
        // and cache it on class
        OSIcon.IconManager.IconProperties iconProp = 
        OSIcon.iconManager.AddEx(drive, IconManager.IconSizeSupported);
        // Do something here!, sample from OSIcon Explorer:
        var item = new ListViewItem(iconProp[IconSize.Small].DisplayName)
        {
            ImageIndex = iconProp[IconSize.Small].ItemIndex
        };
        item.SubItems.Add(string.Empty);
        item.SubItems.Add(iconProp.IconsInfo[IconSize.Small].TypeName);
        item.Tag = drive;
        lvFileExplorer.Items.Add(item);
    }
}
 
// Next function will show path contents
public void ShowPathContents(string path)
{
    if (path == null)
        return;
    // Path is empty so Show MyComputer
    if (path == string.Empty)
    {
        ShowMyComputer();
        return;
    }
    try
    {
        Cursor = Cursors.WaitCursor;
        btnGoUp.Enabled = true;
        RewindManager.Add(path);
        btnGoBack.Enabled = RewindManager.CanPrevious;
        btnGoForward.Enabled = RewindManager.CanForward;
        lbSelected.Text = string.Empty;
        CurrentPath = path;
        lvFileExplorer.BeginUpdate();
        lvFileExplorer.Items.Clear();
        //CreateGoUpFolder(path);
        TotalFilesSize = 0;
        TotalFolders = 0;
        TotalFiles = 0;
        // Loop through folders inside current folder
        foreach (var folder in Directory.EnumerateDirectories(path))
        {
            // Get folder name from path
            var dirInfo = new DirectoryInfo(folder);
            // Remove system directories
            if ((dirInfo.Attributes & FileAttributes.System) == FileAttributes.System)
                continue;
            var item = new ListViewItem(Path.GetFileName(folder)) { Tag = folder };
            var iconProp = IconManager[IconManager.FolderClosed];
            item.ImageIndex = iconProp[IconSize.Small].ItemIndex;
            item.SubItems.Add(dirInfo.LastWriteTime.ToString(CultureInfo.CurrentCulture));
            item.SubItems.Add(iconProp[IconSize.Small].TypeName);
            item.SubItems.Add(string.Empty);
            lvFileExplorer.Items.Add(item);
            TotalFolders++;
        }
        // Loop through Files inside current folder
        foreach (var file in Directory.EnumerateFiles(path))
        {
            // Get some addition file information like size, name, extension, etc...
            var fi = new FileInfo(file);
            // Remove system directories
            if ((fi.Attributes & FileAttributes.System) == FileAttributes.System)
                continue;
            var iconProp = IconManager.AddEx(fi.Extension, IconManager.IconsSizeSupported);
            var item = new ListViewItem(fi.Name)
            {
                Tag = fi.FullName,
                ImageIndex = iconProp[IconSize.Small].ItemIndex
            };
            item.SubItems.Add(fi.LastWriteTime.ToString(CultureInfo.CurrentCulture));
            item.SubItems.Add(iconProp.IconsInfo[IconSize.Small].TypeName);
            item.SubItems.Add(string.Format(" {0:##.##} {1}", 
            Utilities.FormatByteSize(fi.Length), Utilities.GetSizeNameFromBytes(fi.Length, false)));
            lvFileExplorer.Items.Add(item);
            TotalFilesSize += fi.Length;
            TotalFiles++;
        }
        // Lets make some status and retrieve total folders, files and their total size
        string textToSet = string.Empty;
        if (TotalFolders > 0)
            textToSet += string.Format("{0} {1}", TotalFolders, 
            Utilities.ConvertPlural(TotalFolders, "Folder"));
        if (TotalFiles > 0)
        {
            if (textToSet != "Total:")
                textToSet += " &";
            textToSet += string.Format(" {0:##.##} {1} in {2} {3}", 
            Utilities.FormatByteSize(TotalFilesSize), Utilities.GetSizeNameFromBytes
            (TotalFilesSize, false), TotalFiles, Utilities.ConvertPlural(TotalFiles, "File"));
        }
        if (textToSet == "Total:")
            textToSet = "Empty";
        tbAddress.Text = CurrentPath;
        lbTotal.Text = textToSet;
    }
    catch (Exception ex)
    {
        MessageBox.Show(string.Format("Error on trying access: {0}\n\n{1}", path, ex.Message), 
        "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
    }
    finally
    {
        lvFileExplorer.EndUpdate();
        Cursor = Cursors.Default;
        RebuildNavigationHistory();
    }
}

ListView only has an "ImageList" (should be 16 x 16px) and "LargeImageList". If you want to show "ExtraLarge" icons introduced in XP, and "Jumbo" from Vista or above, you have to change "LargeImageList" to the desired size, like:

C#
/* 
* "fileExplorerList" is our ListView
* View:
* 0 = LargeIcons
* 1 = Details
* 2 = Small Icons
* 3 = List
* 4 = Title
* End View Enumeration
* 5 = ExtraLarge
* 6 = Jumbo
*/

private void ChangeListViewV(uint index)
{
    // If view is bigger than 4 means user wants ExtraLarge or Jumbo
    // To show that sizes View must be set to: View.LargeIcon
    // Also we have to change Large ImageList to the desired one
    if (index > 4)
    {
        // we change ImageList because ListView only have ImageList and LargeImageList
        switch (index)
        {
           case 5:
              fileExplorerList.LargeImageList = 
                    iconManager.ImageList[IconReader.IconSize.ExtraLarge];
              break;
           case 6:
              fileExplorerList.LargeImageList = 
                    iconManager.ImageList[IconReader.IconSize.Jumbo];
              break;
        }
        fileExplorerList.View = View.LargeIcon;
        return;
     }
     // View is under normal (small or large)
     // Get back to normal
     fileExplorerList.LargeImageList = iconManager.ImageList[IconReader.IconSize.Large];
     fileExplorerList.View = (View)index;
}

How can you get rid of the added icons? It can be done like so:

C#
// I dont need .txt icon anymore, and i will not use it from ImageList
iconManager.Remove(".txt", true);
// I dont need .wav icon anymore, but i still use it from ImageList
iconManager.Remove(".wav", false);
// IconSize Small is to small and Jumbo is too big for what i want
iconManager.Remove(".exe", IconReader.IconSize.Small | 
                                     IconReader.IconSize.Jumbo, true);

You need not hard-code with the IconManager class. Here is an example:

C#
string name = ".dll";

// Bad Way:
IconProperties iconProp = iconManager.IconList[name];
if(!iconProp.IsValid(name, IconReader.IconSize.Small))
{
    OSIcon.WinAPI.Shell32.SHFILEINFO shfi = new Shell32.SHFILEINFO();
    iconManager.AddEx(name, IconReader.IconSize.Small, ref shfi);
}
if(!iconProp.IsValid(name, IconReader.IconSize.Jumbo))
{
    OSIcon.WinAPI.Shell32.SHFILEINFO shfi = new Shell32.SHFILEINFO();
    iconManager.AddEx(name, IconReader.IconSize.Jumbo, ref shfi);
}

// Good Way:
IconProperties iconProp = iconManager.AddEx(name, IconReader.IconSize.Small | IconReader.IconSize.Jumbo);

History

V3.0

  • Rewrite the code for better performance and usage
  • Added a FileExplorer control that behaves like the Windows explorer
  • Added a strong key to the library
  • Library is now compiled with .NET Framework 4.0

V2.0

  • Added About class
  • Added better commentaries
  • Added more samples
  • Updated sample application to use new icon sizes
  • Updated sample application to use the new library
IconProperties class
  • Added the "Remove" function, to remove an icon from a specified size
    • Supports multi sizes flags (IconReader.IconSize.Small | IconReader.IconSize.Large)
    • Returns a Dictionary<IconReader.IconSize, int> with removed icons, where int is the icon index on the ImageList
  • Added three "IsValid" functions
    • bool IsValidEx(IconReader.IconSize size), same as "IsValid(IconReader.IconSize size)", but also checks if the icon is not NULL
    • bool IsValid(), checks if that instance contains an icon
    • bool IsValid(IconReader.IconSize size), checks if an icon of a specified size exists in that instance
  • Changed "IconsInfo" type from struct to Dictionary<IconReader.IconSize, Shell32.SHFILEINFO>
  • Changed "IconsIndex" type from struct to Dictionary<IconReader.IconSize, int>
  • Changed "Icons" type from struct to Dictionary<IconReader.IconSize, Icon>
  • Implemented a "Tag" object
  • Disposable class
  • "IconProperties" is now a class, was a struct before
IconManager class
  • Fixed the "AddEx" function to allow adding more icons of different sizes
  • Added commentaries
  • Added two "Remove" functions, allows removing icons from the cache and from the ImageList
    • bool Remove(string path, bool removeIconFromList), removes all icons
    • bool Remove(string path, IconReader.IconSize iconSize, bool removeIconFromList), removes icons of a specified size only
  • Added private "Add" function, common actions when adding icons to list (to remove redundancy)
  • Added "IsValidEx" function, same as "IsValid", but returns the matched "IconProperties"; otherwise returns a new instance
  • Added two new constructors:
    • public IconManager(bool createSmallIconList, bool createLargeIconList, bool createExtraLargeIconList, bool createJumboIconList)
    • public IconManager(bool createSmallIconList, bool createLargeIconList, bool createExtraLargeIconList, bool createJumboIconList, bool optimizeToOS)
  • Replaced "ImageListSmall" and "ImageListLarge" ImageLists with "IImageList" Dictionary<IconReader.IconSize, ImageList>
  • Added "IconSizeAllSupported" readonly variable, contains all icon sizes supported by the current OS
  • Added "IconManager.IconSizeAll" constant, contains all icon sizes (Small | Large | ExtraLarge | Jumbo)
IconReader class
  • Changed all functions that contain a "IconReader.IconSize" to support new icon sizes (ExtraLarge, Jumbo)
  • Added the "ExtractIconFromResource" function, extracts an icon by name from the assembly
  • Added the "ExtractIconsFromFile" function, extracts all icons from a file; returns "Icon[]"
  • Added the "ExtractIconFromFileEx" function, identical to ExtractIconFromFile, but supports bigger sizes and icon information
  • Added two new icon sizes to "IconReader.IconSize"
    • IconReader.Iconsize.ExtraLarge (48x48 px.), XP or above supported
    • IconReader.Iconsize.Jumbo (256x256 px.), Vista or above supported
  • Renamed function "ExtractIcon" to "ExtractIconFromFile"
About class
  • Added the "ProjectAuthor" constant, my name
  • Added the "ProjecWWW" constant, this page URL

V1.0.01

  • Modified to correct egregious formatting and spelling errors - JSOP - 01/03/2010

V1.0

  • First release

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)