views:

3024

answers:

5

In .Net (C# or VB: don't care), given a file path string, FileInfo struct, or FileSystemInfo struct for a real existing file, how can I determine the icon(s) used by the shell (explorer) for that file?

I'm not currently planning to use this for anything, but I became curious about how to do it when looking at this question and I thought it would be useful to have archived here on SO.

+11  A: 
Imports System.Drawing
Module Module1

    Sub Main()    
        Dim filePath As String =  "C:\myfile.exe"  
        Dim TheIcon As Icon = IconFromFile(filePath)  

        If TheIcon IsNot Nothing Then    
            ''#Save it to disk, or do whatever you want with it.
            Using stream As New System.IO.FileStream("c:\myfile.ico", IO.FileMode.CreateNew)
                TheIcon.Save(stream)          
            End Using
        End If
    End Sub

    Public Function IconFromFilePath(filePath As String) As Icon
        Dim result As Icon = Nothing
        Try
            result = Icon.ExtractAssociatedIcon(filePath)
        Catch ''# swallow and return nothing. You could supply a default Icon here as well
        End Try
        Return result
    End Function
End Module
Stefan
That's fine for .exes, .dlls, or other files that contain icons. But what about text files or other simple files, where the icon may vary based on what program was installed or a setting the user altered?
Joel Coehoorn
It should work for ALL files that has an associated icon, it does not have to have an assoiciated program what I know.
Stefan
What is returned if there is no associated icon?
Joel Coehoorn
+1 Icon.ExtractAssociatedIcon will return exactly the same icon as the one showed by windows explorer
Wim Coenen
Testing shows this does work. I was unclear on his initial explanation- I thought it only looked for Icon resources within the file itself, but happily this turns out not to be the case.
Joel Coehoorn
Edited to separate code relevant to the question from the application code that tests it
Joel Coehoorn
That really helped!
JaredPar
Awesome! How can I get an icon for a folder ?
modosansreves
+1 from me. That really helped me! I don't mind providing my own icon for a folder, i'm just happy i don't have to use the native API or the Registry. :)
Botz3000
If you want to do the same thing for WPF you can use the Handle property of the System.Drawing.Icon to create a BitmapSource for an Image:image.Source = System.Windows.Interop.Imaging.CreateBitmapSourceFromHIcon( result.Handle, Int32Rect.Empty, BitmapSizeOptions.FromEmptyOptions());Note that ExtractAssociatedIcon always returns the 32x32 pixel version of the icon.
Christian Rodemeyer
A: 

This link seems to have some info. It involves a lot of registry traversing, but it seems doable. The examples are in C++

Jason Punyon
A: 
  • determine extension
  • in registry, go to "HKCR\.{extension}", read the default value (let's call it filetype)
  • in "HKCR\{filetype}\DefaultIcon", read the default value: this is the path to the icon file (or icon container file, like an .exe with an embedded icon resource)
  • if needed, use your preferred method of extracting the icon resource out of the mentioned file

edit/moved up from the comments:

If the icon is in a container file (this is quite common), there will be a counter after the path, like this: "foo.exe,3". This means it is icon number 4 (the index is zero-based) of the available icons. A value of ",0" is implicit (and optional). If the counter is 0 or missing, the fist available icon will be used by the shell.

Tomalak
If it's an icon container file that contains several icons, how do you know which to use?
Joel Coehoorn
There is a counter after the path, like "foo.exe,3". This means it is icon no. 4 (the index is zero-based) of the available icons. A value of ",0" is implicit and therefore optional. If it is missing, the fist available icon will be used by the shell.
Tomalak
The registry is not an API! There are other ways to specify icons, and this method will be wrong. Please use the SHGetFileInfo API for this.
@timbagas: "and this method will be wrong"... Wrong in what way, other than "not using an API"?
Tomalak
+8  A: 

Please ignore everyone telling you to use the registry! The registry is NOT AN API. The API you want is SHGetFileInfo with SHGFI_ICON. You can get a P/Invoke signature here:

http://www.pinvoke.net/default.aspx/shell32.SHGetFileInfo

Since we are after C# or VB, Stefan's answer is much simpler.
Wim Coenen
+3  A: 

You should use SHGetFileInfo.

Icon.ExtractAssociatedIcon works just as well as SHGetFileInfo in most cases, but SHGetFileInfo can work with UNC paths (e.g. a network path like "\\ComputerName\SharedFolder\") while Icon.ExtractAssociatedIcon cannot. If you need or might need to use UNC paths, it would be best to use SHGetFileInfo instead of Icon.ExtractAssociatedIcon.

This is good CodeProject article on how to use SHGetFileInfo.

Zach Johnson