0

I have a file on a binary in the database, which I'm not loading until the user double clicks on the item (with it's Icon)

ExtractAssociatedIcon should be solving this (I've seen it here: ExtractAssociatedIcon returns null)

But this asks for the existance of the document on a path, (which I don't have), How can I associate to the extension of the tentative file (example: "something.docx") which extension the user has associated on his pc to the Icon I should show?

@Edit: I may be able to pull out the content (byte[]) from the database, if that is useful to get the icon asociated to the image. (however, it may also take forever to transfer each file byte[] just to set the icon image).

Also this example of @MatthewWatson is what we are actually using to get it but it takes like 8 seconds on each object value = rkFileIcon.GetValue(""); line, which has 8.4k items to iterate.

@@Edit: Also tried

    public static Icon GetIconOldSchool(string fileName)
    {
        ushort uicon;
        StringBuilder strB = new StringBuilder(fileName);
        IntPtr handle = ExtractAssociatedIcon(IntPtr.Zero, strB, out uicon);
        Icon ico = Icon.FromHandle(handle);

        return ico;
    }

With no success.

@@@Edit: This one above gives me the icon of a file.(and not the docx icon when it gets a .docx)

    [StructLayout(LayoutKind.Sequential)]
    public struct SHFILEINFO
    {
        public IntPtr hIcon;
        public IntPtr iIcon;
        public uint dwAttributes;
        [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)]
        public string szDisplayName;
        [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 80)]
        public string szTypeName;
    };
    static SHFILEINFO shinfo = new SHFILEINFO();
    class Win32
    {
        public const uint SHGFI_ICON = 0x100;
        public const uint SHGFI_LARGEICON = 0x0; // 'Large icon
        public const uint SHGFI_SMALLICON = 0x1; // 'Small icon

        [DllImport("shell32.dll")]
        public static extern IntPtr SHGetFileInfo(string pszPath, uint dwFileAttributes, ref SHFILEINFO psfi, uint cbSizeFileInfo, uint uFlags);
    }
    public static Icon YetAnotherAttempt(string fName)
    {

        //Use this to get the small Icon
        var hImgSmall = Win32.SHGetFileInfo(fName, 0, ref shinfo, (uint)Marshal.SizeOf(shinfo), Win32.SHGFI_ICON | Win32.SHGFI_SMALLICON);

        //Use this to get the large Icon
        //hImgLarge = SHGetFileInfo(fName, 0, 
        //  ref shinfo, (uint)Marshal.SizeOf(shinfo), 
        //  Win32.SHGFI_ICON | Win32.SHGFI_LARGEICON);

        //The icon is returned in the hIcon member of the shinfo struct
        return System.Drawing.Icon.FromHandle(shinfo.hIcon);
    }

@@@@Edit: The results of @AlexK. solution.

enter image description here

The FileToImage Converter is where I'm doing the magic.

     <ListBox.ItemTemplate>
            <DataTemplate>
                <Grid>
                    <Grid.ColumnDefinitions>
                        <ColumnDefinition />
                        <ColumnDefinition />
                    </Grid.ColumnDefinitions>
                    <StackPanel Orientation="Horizontal">
                        <Image Source="{Binding Converter={StaticResource FileToImage}}" />
                        <TextBlock Text="{Binding FileName}"
                               Margin="5,0,0,0"
                               VerticalAlignment="Center"/>
                    </StackPanel>
Community
  • 1
  • 1
apacay
  • 1,702
  • 5
  • 19
  • 41
  • [This may provide some pointers](http://www.codeproject.com/Articles/29137/Get-Registered-File-Types-and-Their-Associated-Ico) – Matthew Watson Nov 12 '14 at 15:44
  • `SHGetFileInfo()` with `SHGFI_USEFILEATTRIBUTES` does not require the passed filename to exist – Alex K. Nov 12 '14 at 15:59
  • @MatthewWatson that was what we already had implemented and somehow it hangs on the `object value = rkFileIcon.GetValue("");` line it takes forever to take the value of each of the 8400 extensions loaded on the registry. I was looking for a workaround. – apacay Nov 12 '14 at 18:41
  • @AlexK. I've tried that, I edited my question with the attempt. – apacay Nov 12 '14 at 19:24

1 Answers1

1

To your Win32 class add:

public const uint SHGFI_USEFILEATTRIBUTES = 0x000000010; // better as private enum

And

[DllImport("user32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
internal static extern bool DestroyIcon(IntPtr hIcon);

Your call becomes:

var hImgSmall = Win32.SHGetFileInfo(fName, 0, ref shinfo, (uint)Marshal.SizeOf(shinfo), 
                Win32.SHGFI_ICON | Win32.SHGFI_SMALLICON | Win32.SHGFI_USEFILEATTRIBUTES);

To return the icon you should copy it then destroy the one the API returned:

var icon = (Icon)Icon.FromHandle(shinfo.hIcon).Clone();    
Win32.DestroyIcon(shinfo.hIcon);
return icon;

Example (WindowsForm proj)

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

namespace WindowsFormsApplication1
{
    public partial class Form1 : Form
    {
        public Form1() {
            InitializeComponent();
        }

        private void Form1_Load(object sender, EventArgs e) {
            var shinfo = new Win32.SHFILEINFO();
            Win32.SHGetFileInfo("0000000000.DOCX", 0, ref shinfo, (uint)Marshal.SizeOf(shinfo), Win32.SHGFI_ICON | Win32.SHGFI_SMALLICON | Win32.SHGFI_USEFILEATTRIBUTES);
            var icon = (Icon)Icon.FromHandle(shinfo.hIcon).Clone();
            Win32.DestroyIcon(shinfo.hIcon);
            this.BackgroundImage = icon.ToBitmap();
            icon.Dispose();
        }

        private class Win32 {
            internal const uint SHGFI_ICON = 0x100;
            internal const uint SHGFI_SMALLICON = 0x1;
            internal const uint SHGFI_USEFILEATTRIBUTES = 0x000000010;

            [DllImport("user32.dll", SetLastError = true)]
            [return: MarshalAs(UnmanagedType.Bool)]
            internal static extern bool DestroyIcon(IntPtr hIcon);

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

            [StructLayout(LayoutKind.Sequential)]
            internal struct SHFILEINFO
            {
                public IntPtr hIcon;
                public IntPtr iIcon;
                public uint dwAttributes;

                [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)]
                public string szDisplayName;

                [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 80)]
                public string szTypeName;
            }
        }
    }
}
Alex K.
  • 171,639
  • 30
  • 264
  • 288