2

I have a great technique to get the associated extension/image in the current system (because extensions can have different images from a system to another). And here is the function:

public static Icon getIconFromFile(string ext, bool large = true)
{
        string fileName = (new Random()).Next(100, 1000).ToString() + ext;
        System.IO.File.Create(fileName);
        System.Drawing.Icon icon;
        SHFILEINFO shinfo = new SHFILEINFO();

        if (large)
        {
            IntPtr hImgLarge = Win32.SHGetFileInfo(fileName, 0, ref shinfo, (uint)Marshal.SizeOf(shinfo), Win32.SHGFI_ICON | Win32.SHGFI_LARGEICON);
            icon = System.Drawing.Icon.FromHandle(shinfo.hIcon);
        }
        else
        {
            IntPtr hImgSmall = Win32.SHGetFileInfo(fileName, 0, ref shinfo, (uint)Marshal.SizeOf(shinfo), Win32.SHGFI_ICON | Win32.SHGFI_SMALLICON);
            icon = System.Drawing.Icon.FromHandle(shinfo.hIcon);
        }
        try
        {
            System.IO.File.Delete(fileName);
        }
        catch(Exception e)
        {
            System.Console.WriteLine(e.StackTrace);
        }
        return icon;
    }

The problem is that the function doesn't close the access to the file, so i can't remove it. How can i do ? Thanks

Johan
  • 74,508
  • 24
  • 191
  • 319
Extaze
  • 1,117
  • 2
  • 10
  • 18
  • Are you sure you don't want to consider other techniques? What if you haven't rights to create files? See [this SO answer](http://stackoverflow.com/a/272044/870604). – ken2k Feb 03 '12 at 22:27
  • Great, but how can i extract ImageSource from ProgramIcon ? – Extaze Feb 04 '12 at 11:21
  • Aren't you leaking the icon handle? better to: Icon.FromHandle(shinfo.hIcon).clone(); DestroyIcon(shinfo.hIcon)` - there is also the native Icon.ExtractAssociatedIcon – Alex K. Feb 04 '12 at 11:37
  • i was talking of one of the classes (ProgramIcon) of http://stackoverflow.com/a/272044/870604 – Extaze Feb 04 '12 at 11:57

2 Answers2

7

You don't need to create a dummy file. Use SHGFI_USEFILEATTRIBUTES.

Raymond Chen
  • 44,448
  • 11
  • 96
  • 135
2

File.Create returns a stream that references the file you've created. To ensure that the stream is closed properly, you should wrap it in a using block:

System.Drawing.Icon icon;
using(var stream = System.IO.File.Create(fileName))
{
    SHFILEINFO shinfo = new SHFILEINFO();

    if (large)
    {
        IntPtr hImgLarge = Win32.SHGetFileInfo(fileName, 0, ref shinfo, (uint)Marshal.SizeOf(shinfo), Win32.SHGFI_ICON | Win32.SHGFI_LARGEICON);
        icon = System.Drawing.Icon.FromHandle(shinfo.hIcon);
    }
    else
    {
        IntPtr hImgSmall = Win32.SHGetFileInfo(fileName, 0, ref shinfo, (uint)Marshal.SizeOf(shinfo), Win32.SHGFI_ICON | Win32.SHGFI_SMALLICON);
        icon = System.Drawing.Icon.FromHandle(shinfo.hIcon);
    }
}
try
{
    System.IO.File.Delete(fileName);
}
catch(Exception e)
{
    System.Console.WriteLine(e.StackTrace);
}
return icon;

It doesn't matter if you use the returned stream or not, you need to ensure it's disposed so that the file can be deleted. Note also that I've moved the declaration of icon to outside the using block so that you can return it at the end of the method.

I should also point out that:

string fileName = (new Random()).Next(100, 1000).ToString() + ext;

Is a bit of a "bad idea" when you could just as easily call "System.IO.Path.GetTempFileName();" and leave creating the file and uniquely naming it to the Operating System, rather than attempting to do that yourself. THat has the added bonus of the file being created in the users temp directory, which is the best place for it given that it's a temporary file. You'd also then not encounter the issue of the file being held open (there are various other methods like System.IO.Path.GetExtension you could use to rename the file so it has the appropriate extension.

Rob
  • 45,296
  • 24
  • 122
  • 150
  • a `using` block is overkill for a value that isn't used, just write `System.IO.File.Create(fileName).Close()`. – Ben Voigt Feb 03 '12 at 22:24
  • @BenVoigt, fair point, I do like to "promote" `using` whenever I can as I sadly see it used all too infrequently. In this example `.Close()` vs `using` is probably a six of one/half a dozen of the other thing =) – Rob Feb 03 '12 at 22:28