Click here to Skip to main content
15,881,742 members
Articles / Programming Languages / C#
Article

IconHandler

Rate me:
Please Sign up or sign in to vote.
4.79/5 (33 votes)
1 Feb 2006CPOL1 min read 166.1K   3.7K   119   42
An icon handling class for icon extraction from files and registry

Icon Handler at work :)

Introduction

IconHandler is a class for getting icons from files and the default associated icons by the extension of the file.

Background

It was originally writtin for a P2P project that never got out, called Kibutz. I decided to add the shell and resource functions becouse of a comment I got here. The const value has also been fixed (check IconSize).

Using the code

The class includes four simple-to-use functions:

  • IconFromFile(Filename,IconSize,Index)
    This will get a single icon from a file with the specific index. If no icon was found or if the index was outside of the bounds, null will be returned.
  • IconsFromFile(Filename,IconSize)
    This will return an Icon typed array of icons.
  • IconFromExtension(Extension,IconSize)
    This will return an icon associated with an extension -- if it exists -- by using Shell API; if not null will be returned.
  • IconFromResource(string ResourceName)
    This will return an icon from the assembly resource if it exists.
C#
/*
/*
 * IconHandler - by Gil Schmidt
 * 
 * - Originaly was writtin for a p2p project called Kibutz.
 * - The IconFromExtension might give you some problems if it won't find an
 *   icon for it( try/catch should be used).
 *
 * [Updated]
 * 
 * - Added Shell function for getting file extension after getting some commet
 *   about it, check link below.
 *   (http://www.codeguru.com/Csharp/Csharp/cs_misc/icons/article.php/c4261/)
 * - IconFromResource was added for having all the common needed functions for 
 *   handling icons.
 * - Readed DestroyIcon and adding GetManagedIcon, after verifying it's needed 
 *   (thanks DrGui and Kenneth Broendum).
 * - Removed the IconFromExtension that pulled the icon from the registry 
 *   (IconFromExtensionShell is default now).
 * - Fixed IconCount mistake (if the number of icon in the file was 0 and the
 *   index that was selected was also 0 the ExtractIconEx still got to run and
 *   crashed (thanks SickLab).
 * - Fixed iIcon (it was changed from IntPtr to int. on x64 systems IntPtr is 
 *   8 bytes which caused the mistake to popup) parameter in SHFILEINFO struct 
 *   (Thanks Stefan Mayr).
 * 
 * contact me at: Gil_Smdt@Hotmail.com
 * 
*/

using System;
using System.Drawing;
using System.Runtime.InteropServices;
using Microsoft.Win32;
using System.Reflection;
using System.IO;

namespace IconHandler
{
    struct SHFILEINFO 
    {
        public IntPtr hIcon;        
        public int iIcon;        
        public uint dwAttributes;    
        [MarshalAs( UnmanagedType.ByValTStr, SizeConst = 260 )]
        public string szDisplayName;
        [MarshalAs( UnmanagedType.ByValTStr, SizeConst = 80 )]
        public string szTypeName;
    };

    public enum IconSize : uint
    {
        Large = 0x0,  //32x32
        Small = 0x1 //16x16        
    }

    //the function that will extract the icons from a file
    public class IconHandler
    {
        const uint SHGFI_ICON = 0x100;
        const uint SHGFI_USEFILEATTRIBUTES    = 0x10;

        [DllImport("Shell32", CharSet=CharSet.Auto)]
        internal extern static int ExtractIconEx (
            [MarshalAs(UnmanagedType.LPTStr)] 
            string lpszFile,                //size of the icon
            int nIconIndex,                 
                //index of the icon (in case we have more 
                //than 1 icon in the file
            IntPtr[] phIconLarge,           //32x32 icon
            IntPtr[] phIconSmall,           //16x16 icon
            int nIcons);                    //how many to get

        [DllImport("shell32.dll")]
        static extern IntPtr SHGetFileInfo(
            string pszPath,                //path
            uint dwFileAttributes,        //attributes
            ref SHFILEINFO psfi,        //struct pointer
            uint cbSizeFileInfo,        //size
            uint uFlags);    //flags

        //we need this function to release the unmanaged resource,
        //the unmanaged resource will be copies to a managed one and 
        //it will be returned.
        [DllImport("user32.dll", CharSet = CharSet.Auto)]
        extern static bool DestroyIcon(IntPtr handle);

        //will return an array of icons 
        public static Icon[] IconsFromFile(string Filename,IconSize Size)
        {
            int IconCount = ExtractIconEx(Filename,-1,null,null,0); 
                //checks how many icons.
            IntPtr[] IconPtr = new IntPtr[IconCount];
            Icon TempIcon;

            //extracts the icons by the size that was selected.
            if (Size == IconSize.Small)
                ExtractIconEx(Filename,0,null,IconPtr,IconCount);
            else
                ExtractIconEx(Filename,0,IconPtr,null,IconCount);

            Icon[] IconList = new Icon[IconCount];
            
            //gets the icons in a list.
            for (int i = 0; i < IconCount; i++)
            {
                TempIcon = (Icon) Icon.FromHandle(IconPtr[i]);
                IconList[i] = GetManagedIcon(ref TempIcon);
            }

            return IconList;
        }

        //extract one selected by index icon from a file.
        public static Icon IconFromFile(
            string Filename,IconSize Size,int Index)
        {
            int IconCount = ExtractIconEx(Filename,-1,null,null,0); 
                //checks how many icons.
            if (IconCount <= 0 || Index >= IconCount) return null; 
                // no icons were found.

            Icon TempIcon;
            IntPtr[] IconPtr = new IntPtr[1];

            //extracts the icon that we want in the selected size.
            if (Size == IconSize.Small)
                ExtractIconEx(Filename,Index,null,IconPtr,1);
            else
                ExtractIconEx(Filename,Index,IconPtr,null,1);

            TempIcon = Icon.FromHandle(IconPtr[0]);

            return GetManagedIcon(ref TempIcon);
        }
        public static Icon IconFromExtension(string Extension,IconSize Size)
        {
            try
            {
                Icon TempIcon;

                //add '.' if nessesry
                if (Extension[0] != '.') Extension = '.' + Extension;

                //temp struct for getting file shell info
                SHFILEINFO TempFileInfo = new SHFILEINFO();
                
                SHGetFileInfo(
                    Extension,
                    0, 
                    ref TempFileInfo,
                    (uint)Marshal.SizeOf(TempFileInfo),
                    SHGFI_ICON | SHGFI_USEFILEATTRIBUTES | (uint) Size);

                TempIcon = (Icon) Icon.FromHandle(TempFileInfo.hIcon);
                return GetManagedIcon(ref TempIcon);
            }
            catch (Exception e)
            {
                System.Diagnostics.Debug.WriteLine(
                    "error while trying to get icon for " + Extension + 
                    " :" + e.Message);
                return null;
            }
        }

        /*
         * this is the built in funcion provided by .Net framework for getting 
         * a file icon, i thought it's worth mentioning.
         * 
        public static Icon IconFromExtension(string Filename)
        {
            return Icon.ExtractAssociatedIcon(Filename);
        }
        */

        public static Icon IconFromResource(string ResourceName)
        {
            Assembly TempAssembly = Assembly.GetCallingAssembly();

            return new Icon(TempAssembly.GetManifestResourceStream(
                ResourceName));
        }

        public static void SaveIconFromImage(
            Image SourceImage,string IconFilename,IconSize DestenationIconSize)
        {
            Size NewIconSize = DestenationIconSize == 
                IconSize.Large ? new Size(32,32) : new Size(16,16);

            Bitmap RawImage = new Bitmap(SourceImage,NewIconSize);
            Icon TempIcon = Icon.FromHandle(RawImage.GetHicon());
            FileStream NewIconStream = new FileStream(
                IconFilename,FileMode.Create);

            TempIcon.Save(NewIconStream);

            NewIconStream.Close();
        }

        public static void SaveIcon(Icon SourceIcon,string IconFilename)
        {
            FileStream NewIconStream = new FileStream(
                IconFilename,FileMode.Create);

            SourceIcon.Save(NewIconStream);

            NewIconStream.Close();                                       
        }

        public static Icon GetManagedIcon(ref Icon UnmanagedIcon)
        {
            Icon ManagedIcon = (Icon) UnmanagedIcon.Clone();

            DestroyIcon(UnmanagedIcon.Handle);

            return ManagedIcon;
        }
    }
}

/* EOF */

Points of interest

What got me to write this was that I didn't find anything like this around. It's not complicated code, but when you want to use icons you don't plan on wasting your time dealing with it a lot. So, it's comfortable to have this little piece of code around.

History

  • 12 January, 2005 - Original version posted
  • 1 February, 2006 - First update
  • 23 May, 2007 - Second update

License

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


Written By
Team Leader
Israel Israel
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
GeneralRe: Destroy Unmanaged Icons Pin
Gil.Schmidt2-Nov-05 21:47
Gil.Schmidt2-Nov-05 21:47 
GeneralRe: Destroy Unmanaged Icons Pin
taoufik13-Jan-06 0:11
taoufik13-Jan-06 0:11 
GeneralRe: Destroy Unmanaged Icons Pin
Patrick Etc.9-Dec-06 6:28
Patrick Etc.9-Dec-06 6:28 
QuestionHow could i.... Pin
tayspen8-Sep-05 15:11
tayspen8-Sep-05 15:11 
AnswerRe: How could i.... Pin
Gil.Schmidt23-Sep-05 8:14
Gil.Schmidt23-Sep-05 8:14 
AnswerRe: How could i.... Pin
Gil.Schmidt23-Sep-05 8:33
Gil.Schmidt23-Sep-05 8:33 
GeneralRe: How could i.... Pin
tayspen23-Sep-05 8:36
tayspen23-Sep-05 8:36 
GeneralDoes not work with some extensions Pin
Clickok14-May-05 10:54
Clickok14-May-05 10:54 
I'm using WinServer2003 SP1 and some extensions like 'pdf' and 'htm' doesn`t work...

I have checked the registry, and the DefaultIcon to 'htmlfile' key have only '%1'. and 'pdffile' doesnot have DefaultIcon key... Frown | :(

GeneralRe: Does not work with some extensions Pin
Gil.Schmidt15-May-05 9:04
Gil.Schmidt15-May-05 9:04 
GeneralRe: Does not work with some extensions Pin
Clickok16-May-05 3:56
Clickok16-May-05 3:56 
GeneralCorrection 2 Pin
Darek Maciejewski8-Apr-05 8:59
Darek Maciejewski8-Apr-05 8:59 
GeneralRe: Correction 2 Pin
Gil.Schmidt8-Apr-05 9:02
Gil.Schmidt8-Apr-05 9:02 
GeneralNice Job Pin
Charlie Williams14-Jan-05 5:06
Charlie Williams14-Jan-05 5:06 
GeneralRe: Nice Job Pin
Gil.Schmidt14-Jan-05 6:25
Gil.Schmidt14-Jan-05 6:25 
GeneralCorrection Pin
David M. Kean12-Jan-05 18:43
David M. Kean12-Jan-05 18:43 
GeneralRe: Correction Pin
Gil.Schmidt16-Jan-05 5:33
Gil.Schmidt16-Jan-05 5:33 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.