Introduction
How can we get the icon of a file if it does not exist? If we only know its name or even its extension, how do we get the icon associated with it? This is a simple project of mine to get the registered file types and the associated icons by reading from Windows Registry. The idea belongs to Aaron Young in his article "Listing the Registered File Extensions and Their Associated Icons" at CodeGuru, but the original source code was in Visual Basic. I know a little bit of VB, so I tried to rewrite it in C#. Thanks very much to Aeron Young!
Background
Because this method reads information from the Windows registry, we need to know some basics.
Firstly, where are the registered file types? They are contained in the key HKEY_CLASSES_ROOT
. Now, you launch the Regedit (some way can be: Start > Run > regedit), and go to that key. You may find a lot of sub keys like this: " .zip ", " .mp3 ", etc. Those are the file types we need. Pay attention to the value named empty (Default) as in the picture below:
The value (Default) is not a file path, you can easily find out that the data of default value (here: NeroPhotoSnapPreview.File7.png ) is the name of another sub key in HKEY_CLASSES_ROOT
. Following is what we can find:
Now, what do you see for the value of DefaultIcon
? That is the path to the file that contains the icon we need! Our tasks now are getting that file path and retrieving it to Windows Form.
Secondly, we need to interact with the Registry. .NET supports class RegistryKey
in Microsoft.Win32
namespace and makes it easy for us to open a registry key and get its values as well as its sub keys. Walking a registry tree is the same as walking a file/folder tree structure, it is very easy!
Thirdly, how to retrieve an icon from a file ? There is a little bit of difficulty here, we need to use an API function: ExtractIcon
, but don't worry! All our works are redefining it in C#, and passing the correct parameters for it. Another choice is the function of ExtractIconEx
, but we will consider the ExtractIcon
first.
Using the Code
I packed all necessary methods and API functions in the class RegisteredFileType
.
The ExtractIcon Method
Here is the ExtractIcon
I redefined in C# by referencing www.pinvoke.net:
[DllImport("shell32.dll", EntryPoint = "ExtractIconA",
CharSet = CharSet.Ansi, SetLastError = true, ExactSpelling = true)]
private static extern IntPtr ExtractIcon
(int hInst, string lpszExeFileName, int nIconIndex);
Be sure that you declared to use the System.Runtime.InteropServices
namespace.
The GetFileTypeAndIcon Method
This is one of the core methods which gets the registered file types and icons from Windows Registry:
Gets registered file types and their associated icon in the system.
public static Hashtable GetFileTypeAndIcon()
{
try
{
RegistryKey rkRoot = Registry.ClassesRoot;
string[] keyNames = rkRoot.GetSubKeyNames();
Hashtable iconsInfo = new Hashtable();
foreach (string keyName in keyNames)
{
if (String.IsNullOrEmpty(keyName))
continue;
int indexOfPoint = keyName.IndexOf(".");
if (indexOfPoint != 0)
continue;
RegistryKey rkFileType = rkRoot.OpenSubKey(keyName);
if (rkFileType == null)
continue;
object defaultValue = rkFileType.GetValue("");
if (defaultValue == null)
continue;
string defaultIcon = defaultValue.ToString() + "\\DefaultIcon";
RegistryKey rkFileIcon = rkRoot.OpenSubKey(defaultIcon);
if (rkFileIcon != null)
{
object value = rkFileIcon.GetValue("");
if (value != null)
{
string fileParam = value.ToString().Replace("\"", "");
iconsInfo.Add(keyName, fileParam);
}
rkFileIcon.Close();
}
rkFileType.Close();
}
rkRoot.Close();
return iconsInfo;
}
catch (Exception exc)
{
throw exc;
}
}
Note that this function returns a Hashtable
, you can store information in an array of string
, but by using Hashtable
we will more conveniently get the icon file name from its file extension. Remember to use Microsoft.Win32
namespace which contains class RegistryKey
.
First of all, we need to get HKEY_CLASSES_ROOT
:
RegistryKey rkRoot = Registry.ClassesRoot;
Next, we get all sub keys of it to get all file types:
string[] keyNames = rkRoot.GetSubKeyNames();
To prevent the sub key that is not a file type (eg: ACLFile
), we detect the dot sign:
int indexOfPoint = keyName.IndexOf(".");
string defaultIcon = defaultValue.ToString() + "\\DefaultIcon";
RegistryKey rkFileIcon = rkRoot.OpenSubKey(defaultIcon);
This will lead us to the key that contains the icon file, the last one is adding this file path and the index of the icon to the hash table as a value and its associating filetype as the key:
iconsInfo.Add(keyName, fileParam);
The EmbeddedIconInfo Struct
Note that the information got by the above method is just draw data. We need a structure to store the information associated with the icon file. Therefore, we create the EmbeddedIconInfo
to pack the necessary information which are the name of file containing the icon and the index of the icon:
public struct EmbeddedIconInfo
{
public string FileName;
public int IconIndex;
}
The getEmbeddedIconInfo Method
This method does some logical operations to obtain an instance of EmbeddedIconInfo
structure:
protected static EmbeddedIconInfo getEmbeddedIconInfo(string fileAndParam)
{
EmbeddedIconInfo embeddedIcon = new EmbeddedIconInfo();
if (String.IsNullOrEmpty(fileAndParam))
return embeddedIcon;
string fileName = String.Empty;
int iconIndex = 0;
string iconIndexString = String.Empty;
int commaIndex = fileAndParam.IndexOf(",");
if (commaIndex > 0)
{
fileName = fileAndParam.Substring(0, commaIndex);
iconIndexString = fileAndParam.Substring(commaIndex + 1);
}
else
fileName = fileAndParam;
if (!String.IsNullOrEmpty(iconIndexString))
{
iconIndex = int.Parse(iconIndexString);
if (iconIndex < 0)
iconIndex = 0; }
embeddedIcon.FileName = fileName;
embeddedIcon.IconIndex = iconIndex;
return embeddedIcon;
}
The ExtractIconFromFile Method
Actually, the method RegisteredFileType.ExtractIconFromFile()
calls the Windows API ExtractIcon
in the background:
public static Icon ExtractIconFromFile (string fileAndParam)
{
try
{
EmbeddedIconInfo embeddedIcon = getEmbeddedIconInfo(fileAndParam);
IntPtr lIcon = ExtractIcon(0, embeddedIcon.FileName,
embeddedIcon.IconIndex);
return Icon.FromHandle(lIcon);
}
catch (Exception exc)
{
throw exc;
}
}
Retrieving To Form
This is the most exciting work to see our achievement!
I created the form IconForm
with the important member, icons Hashtable
:
private Hashtable iconsInfo;
The next step, we simply get all file types and their icons:
this.iconsInfo = RegisteredFileType.GetFileTypeAndIcon();
It's time to show the icons:
private void showIcon(string fileType)
{
try
{
string fileAndParam = (this.icons[fileType]).ToString();
if (String.IsNullOrEmpty(fileAndParam))
return;
Icon icon = null;
icon = RegisteredFileType.ExtractIconFromFile(fileAndParam);
if (icon != null)
{
this.pbIconView.Image = icon.ToBitmap();
}
else this.pbIconView.Image = this.pbIconView.ErrorImage;
}
catch (Exception exc)
{
throw exc;
}
}
To make it more logical, I add another function to do business operations:
private void renderImage()
{
try
{
if (this.lbxFileType.Items.Count <= 0
|| this.lbxFileType.SelectedItem == null)
return;
string fileType = this.lbxFileType.SelectedItem.ToString();
this.showIcon(fileType);
}
catch (Exception exc)
{
throw exc;
}
}
Here is the result:

A New Problem...
Recently, I have received an interesting question: How can we get the 16x16 px icons from these icons? If we use the ExtractIcon
function in this way, it will always return the large size of the icon.
There are many solutions for this. One of the easiest ways is use an ImageList
object to manage the icons and change the image's size by setting up the property ImageSize
.
However, the quality of the images is not very good. This trouble was posted in this site:
Get full quality 16 x 16 icon using Icon.ExtractAssociatedIcon and ImageList [
^]. If you go to this site, you also find out a suggested solution to get full quality small icon. Yet, it seems to me that the suggestion is rather complicated.
In this section, I give you another solution to solve the problem. Instead of using the function ExtractIcon
, we can use the Windows API ExtractIconEx
. This method is more powerful than ExtractIcon
because it creates an array of handles to large or small icons extracted from the specified executable file, DLL, or icon file.
This is the ExtractIconEx
redefined in C#:
[DllImport("shell32.dll", CharSet = CharSet.Auto)]
private static extern uint ExtractIconEx
(string szFileName, int nIconIndex,
IntPtr[] phiconLarge, IntPtr[] phiconSmall, uint nIcons);
We must destroy all icons extracted by ExtractIconEx
by using the DestroyIcon
function:
[DllImport("user32.dll", EntryPoint = "DestroyIcon", SetLastError = true)]
private static unsafe extern int DestroyIcon (IntPtr hIcon);
When I find the definition of ExtractIconEx [^] in www.pinvoke.net, I also see a good example in the site. That's why I use it in this application. Based on the example, I add an overloaded version of the method ExtractIconFromFile
in class RegisteredFileType
:
public static Icon ExtractIconFromFile(string fileAndParam, bool isLarge)
{
unsafe
{
uint readIconCount = 0;
IntPtr[] hDummy = new IntPtr[1] { IntPtr.Zero };
IntPtr[] hIconEx = new IntPtr[1] { IntPtr.Zero };
try
{
EmbeddedIconInfo embeddedIcon =
getEmbeddedIconInfo(fileAndParam);
if (isLarge)
readIconCount = ExtractIconEx
(embeddedIcon.FileName, 0, hIconEx, hDummy, 1);
else
readIconCount = ExtractIconEx
(embeddedIcon.FileName, 0, hDummy, hIconEx, 1);
if (readIconCount > 0 && hIconEx[0] != IntPtr.Zero)
{
Icon extractedIcon =
(Icon)Icon.FromHandle(hIconEx[0]).Clone();
return extractedIcon;
}
else return null;
catch (Exception exc)
{
throw new ApplicationException
("Could not extract icon", exc);
}
finally
{
foreach (IntPtr ptr in hIconEx)
if (ptr != IntPtr.Zero)
DestroyIcon(ptr);
foreach (IntPtr ptr in hDummy)
if (ptr != IntPtr.Zero)
DestroyIcon(ptr);
}
}
}
The code is easy to understand. The unsafe
keyword helps the encapsulated code to run faster. To compile the application with unsafe
code, we must configure the application that allows unmanaged code. In Visual Studio, right click on the project and go to tab "Build":

Now, we make some changes in IconForm
to test the new version of the method ExtractIconFromFile
.
private void showIcon(string fileType)
{
try
{
string fileAndParam = (this.icons[fileType]).ToString();
if (String.IsNullOrEmpty(fileAndParam))
return;
Icon icon = null;
bool isLarge = true;
if (currentSize == ImageSize.Small)
isLarge = false;
icon = RegisteredFileType.ExtractIconFromFile(fileAndParam, isLarge);
if (icon != null)
{
this.pbIconView.Image = icon.ToBitmap();
}
else this.pbIconView.Image = this.pbIconView.ErrorImage;
}
catch (Exception exc)
{
throw exc;
}
}
The ImageSize
is a simple enum
:
public enum ImageSize
{
Small,
Large
}
You can use a boolean variable instead!
Points of Interest
I had added a simple search feature. It is absolutely easy because all the keys and their values were stored in Hashtable
icons, so we can quickly access the searched information like accessing an array.
History
- 7th September, 2008: Initial post
- 18th October, 2009: Add new feature of viewing small size icons