Sunday, August 30, 2009

Get default icon on file/folder

I have found this very neat class which you can extract the default icon of File / Folder. Just to make clear, the class is not for extracting the Icon”s” inside the DLL/EXE file.

So for instance on a DLL file, you’ll get the DLL file type icon. image
if EXE, you’ll get the default company program icon. image

This class by the way is already modified so you can have an option to extract which icon size you like, Large or Small so we don’t have to worry about the platforms which means if the device is QVGA, it’ll extract the 32x32 and 16x16 icons, and if VGA, it’ll extract the 64x64 and 32x32 icons.

so, here’s the class

using System;
using System.Drawing;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Windows.Forms;

namespace Coredll.API
{
// Implements a cache for shell icons that represent specific
// directories or files within the file system.
internal class ShellIconCache
{
public enum IconSize
{
Details, LargeIcon, List, SmallIcon
}

public bool AllowThumbnails = false;
public ImageList ImageList;
private Dictionary<int, int> shellIndexToOurIndex = new Dictionary<int, int>();
private IconSize Size;

/// <summary>
/// Creates a shell icon cache and associates it with a given managed image list.
/// </summary>
/// <param name="imageList">The image list to cache the shell icons in</param>
public ShellIconCache(IconSize iconsize)
{
int sm_x = 0;
int sm_y = 0;

this.Size = iconsize;

if (iconsize == IconSize.LargeIcon)
{
sm_x = SM_CXICON;
sm_y = SM_CYICON;
}
else
{
sm_x = SM_CXSMICON;
sm_y = SM_CYSMICON;
}

// Determine the correct icon size based upon
// the current screen DPI and resolution settings
int cx = GetSystemMetrics(sm_x);
int cy = GetSystemMetrics(sm_y);

// Store the image list and set
// it's size to suit the shell icons
this.ImageList = new ImageList();
this.ImageList.ImageSize = new Size(cx, cy);
}

/// <summary>
/// Returns an icon that should be utilised to represent the specified path
/// within a directory listing.
/// </summary>
/// <param name="path">The path (directory or file name) to fetch an icon for</param>
/// <returns>The index into the image list for the icon associated with the path</returns>
public int this[string path]
{
get
{
// Determine the index of the icon in the system image list
SHFILEINFO shinfo = new SHFILEINFO();
IntPtr hImageList = IntPtr.Zero;

int key = 0;

if (this.Size == IconSize.LargeIcon)
{
hImageList = SHGetFileInfo(path, 0, ref shinfo, (uint)Marshal.SizeOf(shinfo), SHGFI_SYSICONINDEX | SHGFI_LARGEICON);
}
else
{
hImageList = SHGetFileInfo(path, 0, ref shinfo, (uint)Marshal.SizeOf(shinfo), SHGFI_SYSICONINDEX | SHGFI_SMALLICON);
}

// If we haven't fetched this icon yet
if (!shellIndexToOurIndex.ContainsKey(shinfo.iIcon))
{
// Fetch the icon
IntPtr hIcon = ImageList_GetIcon(hImageList, shinfo.iIcon, ILD_NORMAL);
Icon myIcon = Icon.FromHandle(hIcon);
DestroyIcon(hIcon);

// And add it to our managed image list
shellIndexToOurIndex.Add(shinfo.iIcon, ImageList.Images.Count);
ImageList.Images.Add(myIcon);
}

key = shinfo.iIcon;

// Return the index of the icon to use for this path.
return shellIndexToOurIndex[key];
}
}

public void AddIcon(Icon ico)
{
ImageList.Images.Add(ico);
}

public void AddIcon(Image ico)
{
ImageList.Images.Add(ico);
}

#region Platform Invoke
private const uint SHGFI_SYSICONINDEX = 0x000004000; // get system icon index
private const uint SHGFI_SMALLICON = 0x1; // Small icon
private const uint SHGFI_LARGEICON = 0x0; // Small icon

[StructLayout(LayoutKind.Sequential)]
private struct SHFILEINFO
{
public IntPtr hIcon;
public Int32 iIcon;
public uint dwAttributes;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)]
public string szDisplayName;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 80)]
public string szTypeName;
};

[DllImport("coredll.dll")]
private static extern IntPtr SHGetFileInfo(string pszPath, uint dwFileAttributes, ref SHFILEINFO psfi, uint cbSizeFileInfo, uint uFlags);

private const uint ILD_NORMAL = 0x00;

[DllImport("coredll.dll")]
private static extern IntPtr ImageList_GetIcon(IntPtr himl, int i, uint flags);

[DllImport("coredll.dll")]
private static extern int DestroyIcon(IntPtr hIcon);

private const int SM_CXICON = 11;
private const int SM_CYICON = 12;
private const int SM_CXSMICON = 49;
private const int SM_CYSMICON = 50;


[DllImport("coredll.dll")]
private static extern int GetSystemMetrics(int nIndex);
#endregion
}
}

And here’s how to use this class.

Don’t bother adding ImageList on your Listview or Treeview control, you have to use the built-in Imagelist of this class.

// Initialize all the default values and setup of controls here
void InitializeControls()
{
ShellIconCache iconcache16 = new ShellIconCache(ShellIconCache.IconSize.SmallIcon);
ListView1.SmallImageList = iconcache16.ImageList;

// do other important control initialization here
}

// get files from path
void GetFilesFromPath()
{
foreach (string f in Directory.GetFiles(@"\Windows"))
{
thisItem = new ListViewItem();
thisItem.ImageIndex = iconcache16[f];
thisItem.Text = Path.GetFileNameWithoutExtension(f);
thisItem.SubItems.Add(Path.GetExtension(f));
thisItem.Tag = f;
ListView1.Items.Add(thisItem);
}
}

2 comments:

  1. great thing! and so easy to use. i hope that it is not forbidden to use this class.

    ReplyDelete
  2. @Vitik

    yes, you're free to use :)

    ReplyDelete

Note: Only a member of this blog may post a comment.