Click here to Skip to main content
Email Password   helpLost your password?

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:

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

You must Sign In to use this message board.
 
 
Per page   
 FirstPrevNext
GeneralThanks
Muammar©
1:26 6 Jul '09  
Thanks for the great class!


All generalizations are wrong, including this one! (\ /)
(O.o)
(><)

GeneralTransparency
cawoodm
5:12 18 Jun '08  
I'm using the ListView together with an ImageList to display files. I am getting the icons using IconFromExtension but the background of the icon is black.

I tried setting the transparent colour of the ImageList to black but it did not help.
AnswerRe: Transparency
cawoodm
5:18 18 Jun '08  
OK, solved by setting the Color Depth of the ImageList to 32bit. Smile
GeneralRe: Transparency
Muammar©
1:24 6 Jul '09  
That was very nice of you "to share your answer of your problem", I just ran into the same problem and you solved it for me!

Thanks again mate!


All generalizations are wrong, including this one! (\ /)
(O.o)
(><)

Generalhow to get the associated icons in vc .net
itbuff
3:40 6 Nov '06  
how to get the associated icons in vc .net
QuestionSaving a 16x16 icon
ekittykat49
19:53 17 Oct '06  
Great article. Thanks for posting it!

One question. I modified SaveIconFromImage() to save a 16x16 (small) icon instead of a 32x32 icon. However, the file created isn't a valid bitmap. Do I need to change something else in the method?

Kat
GeneralSource project won't build
waveangle
16:23 12 Oct '06  
error CS0117: 'IconHandler.IconHandler' does not contain a definition for 'IconFromExtensionShell'
GeneralRe: Source project won't build
ekittykat49
19:57 17 Oct '06  
I had the same problem. I just commented out that code. Most of the app works without it, but it would be nice to get a real fix.
Question48x48 icons?
lpellerin
7:57 26 Jan '06  
How would I go about extracting the tile-sized icon used by Explorer, if it exists? Is there a shell function to do that or do I have to access the icon file and extract the icon myself?

I tried using the SHGFI_SHELLICONSIZE (0x4) constant instead of SHGFI_LARGEICON (IconSize.Large in your project), to no avail. The doc says this about the SHGFI_SHELLICONSIZE constant:
Modify SHGFI_ICON, causing the function to retrieve a Shell-sized icon. If this flag is not specified the function sizes the icon according to the system metric values. The SHGFI_ICON flag must also be set.
What I'm trying to do (for a personal project) is extract the 48x48 Windows XP (with transparency) or largest/highest quality icon associated with a file extension. I wish to mimic the Tile View in Windows Explorer.

Thanks in advance for any help and nice article!
AnswerRe: 48x48 icons?
Gil_Schmidt
8:05 26 Jan '06  
hi lpellerin

i never got into icons diffrent from 16x16 32x32 but i suggest you take a look at

http://www.codeproject.com/dotnet/MultiIcon.asp[^]

it's a very good icon article

Gil
GeneralRe: 48x48 icons?
lpellerin
8:21 26 Jan '06  
Thanks a lot for the tip! It looks like a very good article indeed. I should be able to figure this out by combining the info in both articles.

Thanks again!

- Louis
GeneralA bug fix
SickLab
14:17 5 Jan '06  
Hey,

In the IconFromFile function,

int IconCount = ExtractIconEx(Filename, -1, null, null, 0); //checks how many icons.
if (IconCount < Index) return null; // no icons was found.

It should be:

if (IconCount <= 0 || Index >= IconCount)
Because if we ask for the first Icon in the file, wich would be: 0, and if there is no icons in the file, the IconCount will be equal to 0 too, wich would no enter the if statement, and continue with a null icon handle, making the GetManagedIcon function to crash.

Thanks for this great class.
GeneralRe: A bug fix
Gil_Schmidt
5:03 11 Jan '06  
hi SickLab

thanks for the commet i'm sending an updated version right now

Gil
GeneralRe: A bug fix
hg000000
7:18 31 Jan '06  
You put it the wrong way:

if (IconCount >= 0 || Index >= IconCount) return null; // no icons were found.

should be:

if (IconCount <= 0 || Index >= IconCount) return null; // no icons were found.

Smile

-<>-
GeneralRe: A bug fix
Gil_Schmidt
8:09 31 Jan '06  
fix is on the way
QuestionIcon by extension does not work on my machine
Kenneth Broendum
1:34 10 Nov '05  
Hi there.

The Icon By Extension part does not work on my machine at all ???
I have tried IconFromExtension and IconFromExtensionShell, neither works.

It is the part

IconDisplay.Image = IconHandler.IconFromExtensionShell(DestExt.Text,IconSize.Large).ToBitmap();

or

IconDisplay.Image = IconHandler.IconFromExtension(DestExt.Text,IconSize.Large).ToBitmap();

that throws an exception complaining about an invalid parameter.

Inspecting the Clone in the GetManagedIcon shows: Clone.iconData is <undefined value>.
Don't know if that helps.

I'm running:
XP Professional v 5.1 SP2
Microsoft Development Environment 2003 Version 7.1.3088
Microsoft .NET Framework 1.1 Version 1.1.4322 SP1

Can you help ?

Thanks for an otherwise excellent article. Confused

-- modified at 6:48 Thursday 10th November, 2005
AnswerRe: Icon by extension does not work on my machine
Gil_Schmidt
1:46 10 Nov '05  
dude i just recheck the example file and it works just fine did you run the original code or did you try to use it somewhere else?

btw i also checked it on .Net 2.0 and it's working fine what you should do it trace the code and go line by line and see what causes the error if you can give me some more detail i can try and check it out

adios
GeneralRe: Icon by extension does not work on my machine
Kenneth Broendum
2:29 10 Nov '05  
I ran the original code exactly as I downloaded it from CodeProject. When that did not work I tried to modify it to call IconFromExtension instead. Same result.

Inspection in the debugger gave the following result:

When IconFromExtension and IconFromExtensionShell calls GetManagedIcon we end up with and Icon that has ownHandle = false.

When we store icons in IconList in IconsFromFile we store icons with ownHandle = false.

Does that tell you anything ?

I'm still confused.Confused

Kenneth


GeneralRe: Icon by extension does not work on my machine
Gil_Schmidt
2:43 10 Nov '05  
ok i'm sending a fixed version of it right now, but you can just remove the
DestroyIcon(hIcon); line from GetManagedIcon and it should be fine.
GeneralRe: Icon by extension does not work on my machine
Kenneth Broendum
2:58 10 Nov '05  
Thanks a lot. Now it works.

But has this only been a problem on my machine ?

I can read from some of the other comments that it seems to be running on their machines.

KennethSmile


GeneralRe: Icon by extension does not work on my machine
Gil_Schmidt
3:57 10 Nov '05  
well getting icons from files worked and by extension didn't but as you can see in previous commets the DestroyIcon function isn't nessery in C#
GeneralRe: Icon by extension does not work on my machine
Kenneth Broendum
10:14 10 Nov '05  
Fair enough, I could have been more thorough in my investigation.
Thanks anyway for the fast response. Just voted 5 for your article. Was a great help to me.Smile
GeneralRe: Icon by extension does not work on my machine
Gil_Schmidt
1:28 13 Jan '06  
hi Keeneth

after looking it up again now i think you and DrGui are right, i found this:

http://msdn2.microsoft.com/en-us/library/system.drawing.icon.fromhandle.aspx[^]

reference of FromHandle in msdn and in the remark they said that DestroyIcon needs to be called afer finishing up with the icon.

thanks for the commet an update will be sent soon
GeneralDestroy Unmanaged Icons
DrGUI
7:11 30 Oct '05  
Hi; class looking good Smile

However, you don't seem to destroy the unmanaged icons. I remember MSDN saying that you should release all the icons with DestroyIcon. Mattias Sjögren (http://www.msjogren.net/dotnet/[^]) an MVP, creates the icon from the handle, clones it (this cloned icon is the one returned), disposes the original icon then releases the handle with DestroyIcon.

Actually, code is worth a thousand words: (btw, I just invented that so it's copyright me, and I'll be famous Laugh )
// Return a cloned Icon, because we have to free the original ourselves.
Icon icon = Icon.FromHandle(hIcon);
Icon clone = icon.Clone() as Icon;
icon.Dispose();
Native.DestroyIcon(hIcon);
return clone;

GeneralRe: Destroy Unmanaged Icons
Gil_Schmidt
9:20 30 Oct '05  
thanks for the commet i'm sending an update version right away..

Gil


Last Updated 1 Feb 2006 | Advertise | Privacy | Terms of Use | Copyright © CodeProject, 1999-2010