65.9K
CodeProject is changing. Read more.
Home

IconHandler

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.79/5 (30 votes)

Jan 12, 2005

CPOL

1 min read

viewsIcon

169123

downloadIcon

3697

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.
/*
/*
 * 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