mardi 19 mars 2013

ASP.NET : récupérer des icônes de fichier

Si vous utilisez une application comme SharePoint, ou si vous créez vous même une application web permettant de gérer des fichiers, vous pouvez vouloir récupérer les icônes associées à différents types de fichier pour les utiliser dans vos affichages.

En s'appuyant sur l'article "How to use the SHGetFileInfo function to get the icons that are associated with files in Visual C# .NET", il est possible de créer une application console très simple qui va extraire les icônes en fonction du type de fichier avant de les enregistrer au format PNG. Il est alors possible de copier ces fichiers vers votre site pour les exploiter (via une balise img, un contrôle asp:Image ou le fichier DocIcon.xml de SharePoint). L'extraction directe des icônes sur un serveur web ne fonctionnerait pas, les logiciels correspondants n'étant pas installés.

Le code utilise donc les mêmes fonctions de base, en créant pour les extensions voulues un fichier temporaire. La fonction SHGetFileInfo permet ensuite de récupérer l'icône correspondante avant de la sauver vers un fichier PNG. Le fichier temporaire et l'icône sont alors détruits. Au final le code est donc :

using System;
using System.Diagnostics;
using System.Drawing;
using System.Runtime.InteropServices;
class Program
{
    [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;
    };

    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);
        [DllImport("user32.dll")]
        public static extern bool DestroyIcon(IntPtr Handle);
    }

    static void Main(string[] args)
    {
        IntPtr hImgSmall; //the handle to the system image list
        //IntPtr hImgLarge; //the handle to the system image list
        string fName; //  'the file name to get icon from
        SHFILEINFO shinfo = new SHFILEINFO();

        string[] Extensions={
                                ".default",
                                ".doc",".docm",".docx",
                                ".dwg",
                                ".pdf",
                                ".xls",".xlsm",".xlsx",
                            };
        foreach (var extension in Extensions)
        {
            fName=System.IO.Path.GetTempPath()+"temp"+extension;
            System.IO.File.WriteAllText(fName, "");
            //Use this to get the small Icon
            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
            using (System.Drawing.Icon myIcon = System.Drawing.Icon.FromHandle(shinfo.hIcon))
            {
                using (Bitmap b = myIcon.ToBitmap())
                {
                    b.Save(extension.Substring(1) + ".png", System.Drawing.Imaging.ImageFormat.Png);
                }
            }
            Debug.Assert(Win32.DestroyIcon(shinfo.hIcon));
            System.IO.File.Delete(fName);
        }
        Console.WriteLine("Terminé.");
#if DEBUG
        Console.ReadKey();
#endif
    }
}

Après exécution, vous disposez alors dans le dossier courant (généralement bin\Debug si vous exécutez le code depuis Visual Studio), d'un fichier PNG pour chaque extension indiquée.