正如在这个关于获取常见文件类型图标的问题中所看到的,Windows程序很可能使用C++ Shell API获取已注册文件类型的图标.这些图标可能存在于磁盘上,也可能不存在 - 例如,我们想要创建自己的自定义文件浏览器,并希望在文件中显示与系统相关的图标.
是否有本地C#方式获取各种文件类型的图标(如果是,如何)或必须通过带有shell API的PInvoke来完成?
作为后续工作,如果有一种原生的.NET方式,那么有没有跨平台的方式呢?
我的一个旧的开源项目包括一个完全相同的Icon类,随意撕开它,看到我把这个文件放在公共领域的年龄无论如何它只是PInvoke大部分.
要获取您使用的图标,例如:
Icon zipIcon = BlackFox.Win32.Icons.IconFromExtension(".zip", SystemIconSize.Small);
完整样本:
using System; using System.Windows.Forms; using BlackFox.Win32; using System.Drawing; class Program { static void Main(string[] args) { PictureBox pict = new PictureBox(); pict.Image = Icons.IconFromExtension(".zip", Icons.SystemIconSize.Large).ToBitmap(); pict.Dock = DockStyle.Fill; pict.SizeMode = PictureBoxSizeMode.CenterImage; Form form = new Form(); form.Controls.Add(pict); Application.Run(form); } }
图书馆 :
using System; using System.Drawing; using System.Runtime.InteropServices; using Microsoft.Win32; using System.Reflection; using System.Collections.Generic; namespace BlackFox.Win32 { public static class Icons { #region Custom exceptions class public class IconNotFoundException : Exception { public IconNotFoundException(string fileName, int index) : base(string.Format("Icon with Id = {0} wasn't found in file {1}", index, fileName)) { } } public class UnableToExtractIconsException : Exception { public UnableToExtractIconsException(string fileName, int firstIconIndex, int iconCount) : base(string.Format("Tryed to extract {2} icons starting from the one with id {1} from the \"{0}\" file but failed", fileName, firstIconIndex, iconCount)) { } } #endregion #region DllImports ////// Contains information about a file object. /// struct SHFILEINFO { ////// Handle to the icon that represents the file. You are responsible for /// destroying this handle with DestroyIcon when you no longer need it. /// public IntPtr hIcon; ////// Index of the icon image within the system image list. /// public IntPtr iIcon; ////// Array of values that indicates the attributes of the file object. /// For information about these values, see the IShellFolder::GetAttributesOf /// method. /// public uint dwAttributes; ////// String that contains the name of the file as it appears in the Microsoft /// Windows Shell, or the path and file name of the file that contains the /// icon representing the file. /// [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)] public string szDisplayName; ////// String that describes the type of file. /// [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 80)] public string szTypeName; }; [Flags] enum FileInfoFlags : int { ////// Retrieve the handle to the icon that represents the file and the index /// of the icon within the system image list. The handle is copied to the /// hIcon member of the structure specified by psfi, and the index is copied /// to the iIcon member. /// SHGFI_ICON = 0x000000100, ////// Indicates that the function should not attempt to access the file /// specified by pszPath. Rather, it should act as if the file specified by /// pszPath exists with the file attributes passed in dwFileAttributes. /// SHGFI_USEFILEATTRIBUTES = 0x000000010 } ////// Creates an array of handles to large or small icons extracted from /// the specified executable file, dynamic-link library (DLL), or icon /// file. /// /// /// Name of an executable file, DLL, or icon file from which icons will /// be extracted. /// /// ////// Specifies the zero-based index of the first icon to extract. For /// example, if this value is zero, the function extracts the first /// icon in the specified file. /// ////// If this value is ?1 and ///and /// are both NULL, the function returns /// the total number of icons in the specified file. If the file is an /// executable file or DLL, the return value is the number of /// RT_GROUP_ICON resources. If the file is an .ico file, the return /// value is 1. /// /// Windows 95/98/Me, Windows NT 4.0 and later: If this value is a /// negative number and either /// /// /// An array of icon handles that receives handles to the large icons /// extracted from the file. If this parameter is NULL, no large icons /// are extracted from the file. /// /// /// An array of icon handles that receives handles to the small icons /// extracted from the file. If this parameter is NULL, no small icons /// are extracted from the file. /// /// /// Specifies the number of icons to extract from the file. /// ///or /// is not NULL, the function begins by /// extracting the icon whose resource identifier is equal to the /// absolute value of . For example, use -3 /// to extract the icon whose resource identifier is 3. /// /// If the [DllImport("Shell32", CharSet = CharSet.Auto)] extern static int ExtractIconEx( [MarshalAs(UnmanagedType.LPTStr)] string lpszFile, int nIconIndex, IntPtr[] phIconLarge, IntPtr[] phIconSmall, int nIcons); [DllImport("Shell32", CharSet = CharSet.Auto)] extern static IntPtr SHGetFileInfo( string pszPath, int dwFileAttributes, out SHFILEINFO psfi, int cbFileInfo, FileInfoFlags uFlags); #endregion ///parameter is -1, the /// parameter is NULL, and the /// parameter is NULL, then the return /// value is the number of icons contained in the specified file. /// Otherwise, the return value is the number of icons successfully /// extracted from the file. /// /// Two constants extracted from the FileInfoFlags, the only that are /// meaningfull for the user of this class. /// public enum SystemIconSize : int { Large = 0x000000000, Small = 0x000000001 } ////// Get the number of icons in the specified file. /// /// Full path of the file to look for. ///static int GetIconsCountInFile(string fileName) { return ExtractIconEx(fileName, -1, null, null, 0); } #region ExtractIcon-like functions public static void ExtractEx(string fileName, List largeIcons, List smallIcons, int firstIconIndex, int iconCount) { /* * Memory allocations */ IntPtr[] smallIconsPtrs = null; IntPtr[] largeIconsPtrs = null; if (smallIcons != null) { smallIconsPtrs = new IntPtr[iconCount]; } if (largeIcons != null) { largeIconsPtrs = new IntPtr[iconCount]; } /* * Call to native Win32 API */ int apiResult = ExtractIconEx(fileName, firstIconIndex, largeIconsPtrs, smallIconsPtrs, iconCount); if (apiResult != iconCount) { throw new UnableToExtractIconsException(fileName, firstIconIndex, iconCount); } /* * Fill lists */ if (smallIcons != null) { smallIcons.Clear(); foreach (IntPtr actualIconPtr in smallIconsPtrs) { smallIcons.Add(Icon.FromHandle(actualIconPtr)); } } if (largeIcons != null) { largeIcons.Clear(); foreach (IntPtr actualIconPtr in largeIconsPtrs) { largeIcons.Add(Icon.FromHandle(actualIconPtr)); } } } public static List ExtractEx(string fileName, SystemIconSize size, int firstIconIndex, int iconCount) { List iconList = new List (); switch (size) { case SystemIconSize.Large: ExtractEx(fileName, iconList, null, firstIconIndex, iconCount); break; case SystemIconSize.Small: ExtractEx(fileName, null, iconList, firstIconIndex, iconCount); break; default: throw new ArgumentOutOfRangeException("size"); } return iconList; } public static void Extract(string fileName, List largeIcons, List smallIcons) { int iconCount = GetIconsCountInFile(fileName); ExtractEx(fileName, largeIcons, smallIcons, 0, iconCount); } public static List Extract(string fileName, SystemIconSize size) { int iconCount = GetIconsCountInFile(fileName); return ExtractEx(fileName, size, 0, iconCount); } public static Icon ExtractOne(string fileName, int index, SystemIconSize size) { try { List iconList = ExtractEx(fileName, size, index, 1); return iconList[0]; } catch (UnableToExtractIconsException) { throw new IconNotFoundException(fileName, index); } } public static void ExtractOne(string fileName, int index, out Icon largeIcon, out Icon smallIcon) { List smallIconList = new List (); List largeIconList = new List (); try { ExtractEx(fileName, largeIconList, smallIconList, index, 1); largeIcon = largeIconList[0]; smallIcon = smallIconList[0]; } catch (UnableToExtractIconsException) { throw new IconNotFoundException(fileName, index); } } #endregion //this will look throw the registry //to find if the Extension have an icon. public static Icon IconFromExtension(string extension, SystemIconSize size) { // Add the '.' to the extension if needed if (extension[0] != '.') extension = '.' + extension; //opens the registry for the wanted key. RegistryKey Root = Registry.ClassesRoot; RegistryKey ExtensionKey = Root.OpenSubKey(extension); ExtensionKey.GetValueNames(); RegistryKey ApplicationKey = Root.OpenSubKey(ExtensionKey.GetValue("").ToString()); //gets the name of the file that have the icon. string IconLocation = ApplicationKey.OpenSubKey("DefaultIcon").GetValue("").ToString(); string[] IconPath = IconLocation.Split(','); if (IconPath[1] == null) IconPath[1] = "0"; IntPtr[] Large = new IntPtr[1], Small = new IntPtr[1]; //extracts the icon from the file. ExtractIconEx(IconPath[0], Convert.ToInt16(IconPath[1]), Large, Small, 1); return size == SystemIconSize.Large ? Icon.FromHandle(Large[0]) : Icon.FromHandle(Small[0]); } public static Icon IconFromExtensionShell(string extension, SystemIconSize size) { //add '.' if nessesry if (extension[0] != '.') extension = '.' + extension; //temp struct for getting file shell info SHFILEINFO fileInfo = new SHFILEINFO(); SHGetFileInfo( extension, 0, out fileInfo, Marshal.SizeOf(fileInfo), FileInfoFlags.SHGFI_ICON | FileInfoFlags.SHGFI_USEFILEATTRIBUTES | (FileInfoFlags)size); return Icon.FromHandle(fileInfo.hIcon); } public static Icon IconFromResource(string resourceName) { Assembly assembly = Assembly.GetCallingAssembly(); return new Icon(assembly.GetManifestResourceStream(resourceName)); } /// /// Parse strings in registry who contains the name of the icon and /// the index of the icon an return both parts. /// /// The full string in the form "path,index" as found in registry. /// The "path" part of the string. /// The "index" part of the string. public static void ExtractInformationsFromRegistryString( string regString, out string fileName, out int index) { if (regString == null) { throw new ArgumentNullException("regString"); } if (regString.Length == 0) { throw new ArgumentException("The string should not be empty.", "regString"); } index = 0; string[] strArr = regString.Replace("\"", "").Split(','); fileName = strArr[0].Trim(); if (strArr.Length > 1) { int.TryParse(strArr[1].Trim(), out index); } } public static Icon ExtractFromRegistryString(string regString, SystemIconSize size) { string fileName; int index; ExtractInformationsFromRegistryString(regString, out fileName, out index); return ExtractOne(fileName, index, size); } } }
请查看:http://mvolo.com/display-pretty-file-icons-in-your-aspnet-applications-with-iconhandler/
这不是最干净的解决方案,但它有效.否则,请尝试使用基于mime类型或文件扩展名的图标库.
我相信你已经为你的问题找到了解决方案,但为了其他人的利益,我对VirtualBlackFox的解决方案进行了一些修改.
只需替换IconFromExtension方法......
public static Icon IconFromExtension(string extension, SystemIconSize size) { // Add the '.' to the extension if needed if (extension[0] != '.') extension = '.' + extension; //opens the registry for the wanted key. RegistryKey Root = Registry.ClassesRoot; RegistryKey ExtensionKey = Root.OpenSubKey(extension); ExtensionKey.GetValueNames(); RegistryKey ApplicationKey = Root.OpenSubKey(ExtensionKey.GetValue("").ToString()); RegistryKey CurrentVer = null; try { CurrentVer = Root.OpenSubKey(ApplicationKey.OpenSubKey("CurVer").GetValue("").ToString()); } catch (Exception ex) { //current version not found... carry on without it? } if (CurrentVer != null) ApplicationKey = CurrentVer; //gets the name of the file that have the icon. string IconLocation = ApplicationKey.OpenSubKey("DefaultIcon").GetValue("").ToString(); string[] IconPath = IconLocation.Split(','); IntPtr[] Large = null; IntPtr[] Small = null; int iIconPathNumber = 0; if (IconPath.Length > 1) iIconPathNumber = 1; else iIconPathNumber = 0; if (IconPath[iIconPathNumber] == null) IconPath[iIconPathNumber] = "0"; Large = new IntPtr[1]; Small = new IntPtr[1]; //extracts the icon from the file. if (iIconPathNumber > 0) { ExtractIconEx(IconPath[0], Convert.ToInt16(IconPath[iIconPathNumber]), Large, Small, 1); } else { ExtractIconEx(IconPath[0], Convert.ToInt16(0), Large, Small, 1); } return size == SystemIconSize.Large ? Icon.FromHandle(Large[0]) : Icon.FromHandle(Small[0]); }