As seen in This SO question on getting icons for common file types, it's quite possible for a windows program to get the icons for a registered file type using the C++ Shell API. These icons may or may not exist on disk - for example, we wanted to make our own custom file browser and want to display the system-associated icon with the file.
就像在这个问题中看到的一样,对于普通文件类型的图标,windows程序很有可能使用c++ Shell API来获得注册文件类型的图标。这些图标可能存在于磁盘上,也可能不存在——例如,我们想创建自己的自定义文件浏览器,并希望将系统关联的图标显示在文件中。
Is there a native C# way to get the icons for various file types (and if so, how) or must it be done through PInvoke with shell API?
是否有一个本机c#方法来获取各种文件类型的图标(如果是,如何),或者必须通过使用shell API的PInvoke来完成?
And as a follow up, if there is a native .NET way of doing it, is there a cross-platform way of doing it?
作为一个后续,如果有一个原生的。net的方法,有一个跨平台的方法吗?
6 个解决方案
#1
7
Take a look at: http://mvolo.com/display-pretty-file-icons-in-your-aspnet-applications-with-iconhandler/
看一看:http://mvolo.com/display-pretty-file-icon -in-your-aspnet-application -with-iconhandler/。
It's not the cleanest solution but it works. Otherwise, try to get your hands on a library of Icons that's based on mime type or file extension.
这并不是最干净的解决方案,但确实有效。否则,请尝试使用基于mime类型或文件扩展的图标库。
#2
37
One of my old open source project include an Icon class that does exactly that, feel free to rip it, seeing the age I put this file in the public domain anyway it's just PInvoke for most part.
我的一个旧的开放源码项目包括一个图标类,它可以做到这一点,可以随意地删除它,看到我把这个文件放到公共域中的年龄,不管怎样,它只是大部分的PInvoke。
To get an icon you use for example :
为了得到一个图标,你可以使用例如:
Icon zipIcon = BlackFox.Win32.Icons.IconFromExtension(".zip", SystemIconSize.Small);
Full sample :
完整的示例:
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);
}
}
The library :
图书馆:
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
/// <summary>
/// Contains information about a file object.
/// </summary>
struct SHFILEINFO
{
/// <summary>
/// Handle to the icon that represents the file. You are responsible for
/// destroying this handle with DestroyIcon when you no longer need it.
/// </summary>
public IntPtr hIcon;
/// <summary>
/// Index of the icon image within the system image list.
/// </summary>
public IntPtr iIcon;
/// <summary>
/// Array of values that indicates the attributes of the file object.
/// For information about these values, see the IShellFolder::GetAttributesOf
/// method.
/// </summary>
public uint dwAttributes;
/// <summary>
/// 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.
/// </summary>
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)]
public string szDisplayName;
/// <summary>
/// String that describes the type of file.
/// </summary>
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 80)]
public string szTypeName;
};
[Flags]
enum FileInfoFlags : int
{
/// <summary>
/// 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.
/// </summary>
SHGFI_ICON = 0x000000100,
/// <summary>
/// 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.
/// </summary>
SHGFI_USEFILEATTRIBUTES = 0x000000010
}
/// <summary>
/// Creates an array of handles to large or small icons extracted from
/// the specified executable file, dynamic-link library (DLL), or icon
/// file.
/// </summary>
/// <param name="lpszFile">
/// Name of an executable file, DLL, or icon file from which icons will
/// be extracted.
/// </param>
/// <param name="nIconIndex">
/// <para>
/// 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.
/// </para>
/// <para>
/// If this value is �1 and <paramref name="phiconLarge"/> and
/// <paramref name="phiconSmall"/> 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.
/// </para>
/// <para>
/// Windows 95/98/Me, Windows NT 4.0 and later: If this value is a
/// negative number and either <paramref name="phiconLarge"/> or
/// <paramref name="phiconSmall"/> is not NULL, the function begins by
/// extracting the icon whose resource identifier is equal to the
/// absolute value of <paramref name="nIconIndex"/>. For example, use -3
/// to extract the icon whose resource identifier is 3.
/// </para>
/// </param>
/// <param name="phIconLarge">
/// 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.
/// </param>
/// <param name="phIconSmall">
/// 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.
/// </param>
/// <param name="nIcons">
/// Specifies the number of icons to extract from the file.
/// </param>
/// <returns>
/// If the <paramref name="nIconIndex"/> parameter is -1, the
/// <paramref name="phIconLarge"/> parameter is NULL, and the
/// <paramref name="phiconSmall"/> 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.
/// </returns>
[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
/// <summary>
/// Two constants extracted from the FileInfoFlags, the only that are
/// meaningfull for the user of this class.
/// </summary>
public enum SystemIconSize : int
{
Large = 0x000000000,
Small = 0x000000001
}
/// <summary>
/// Get the number of icons in the specified file.
/// </summary>
/// <param name="fileName">Full path of the file to look for.</param>
/// <returns></returns>
static int GetIconsCountInFile(string fileName)
{
return ExtractIconEx(fileName, -1, null, null, 0);
}
#region ExtractIcon-like functions
public static void ExtractEx(string fileName, List<Icon> largeIcons,
List<Icon> 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<Icon> ExtractEx(string fileName, SystemIconSize size,
int firstIconIndex, int iconCount)
{
List<Icon> iconList = new List<Icon>();
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<Icon> largeIcons, List<Icon> smallIcons)
{
int iconCount = GetIconsCountInFile(fileName);
ExtractEx(fileName, largeIcons, smallIcons, 0, iconCount);
}
public static List<Icon> 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<Icon> 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<Icon> smallIconList = new List<Icon>();
List<Icon> largeIconList = new List<Icon>();
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));
}
/// <summary>
/// Parse strings in registry who contains the name of the icon and
/// the index of the icon an return both parts.
/// </summary>
/// <param name="regString">The full string in the form "path,index" as found in registry.</param>
/// <param name="fileName">The "path" part of the string.</param>
/// <param name="index">The "index" part of the string.</param>
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);
}
}
}
#3
5
I'm sure you have already found a solution for your problems but for the benefit of others i have made some modifications to VirtualBlackFox's solution.
我相信你已经找到了解决问题的方法,但是为了其他人的利益,我已经对VirtualBlackFox的解决方案做了一些修改。
Just replace the IconFromExtension method...
只需替换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]);
}
#4
4
Icon.ExtractAssociatedIcon() won't do the trick. As MSDN states it only extracts icons contained in the file. So creating dummy files won't help either. To my best knowledge you have to go the p/invoke way to get to these icons. A question related to this is this. MaLio seems to have a quite complete example of how to get the icons with p/invoke.
我不会做这个魔术的。作为MSDN,它只提取文件中包含的图标。所以创建虚拟文件也无济于事。据我所知,您必须使用p/invoke方法才能到达这些图标。与此相关的一个问题是。MaLio似乎有一个非常完整的例子,说明如何使用p/invoke来获取图标。
I don't know of a platform agnostic way to do this either (and I don't think there is one).
我也不知道一个平台不可知的方法(我不认为有这样的方法)。
Sorry i couldn't provide you with better news!
对不起,我不能给你提供更好的消息!
#5
3
This class should do the job. Pass either a filename (with path) or folder name (with path).
这个类应该做这个工作。传递文件名(带有路径)或文件夹名(带有路径)。
public static class FileIcon
{
[DllImport("shell32.dll")]
private static extern IntPtr SHGetFileInfo(string pszPath, uint dwFileAttributes, ref SHFILEINFO psfi, uint cbSizeFileInfo, uint uFlags);
[StructLayout(LayoutKind.Sequential)]
private 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;
};
private const uint SHGFI_ICON = 0x100;
private const uint SHGFI_LARGEICON = 0x0; // 'Large icon
private const uint SHGFI_SMALLICON = 0x1; // 'Small icon
public static System.Drawing.Icon GetLargeIcon(string file)
{
FileIcon.SHFILEINFO shinfo = new FileIcon.SHFILEINFO();
IntPtr hImgLarge = FileIcon.SHGetFileInfo(file, 0, ref shinfo, (uint)Marshal.SizeOf(shinfo), FileIcon.SHGFI_ICON | FileIcon.SHGFI_LARGEICON);
return System.Drawing.Icon.FromHandle(shinfo.hIcon);
}
public static System.Drawing.Icon GetSmallIcon(string file)
{
FileIcon.SHFILEINFO shinfo = new FileIcon.SHFILEINFO();
IntPtr hImgLarge = FileIcon.SHGetFileInfo(file, 0, ref shinfo, (uint)Marshal.SizeOf(shinfo), FileIcon.SHGFI_ICON | FileIcon.SHGFI_SMALLICON);
return System.Drawing.Icon.FromHandle(shinfo.hIcon);
}
}
#6
3
Instead of browsing through registry, one may use the IQueryAssociations interface. This interface can also be used to get more information about registered file types (see i.e. ASSOCSTR type). Below I attach code which replaces IconFromExtension method from VirtualBlackFox's solution (parts of his code are left untouched):
与其浏览注册表,还可以使用IQueryAssociations接口。该接口还可以用于获取关于注册文件类型的更多信息(参见:ASSOCSTR类型)。下面我附上了代码,它用VirtualBlackFox的解决方案替换了IconFromExtension方法(他的代码部分未被修改):
public static Icon IconFromExtension(string extension, SystemIconSize size)
{
if (extension[0] != '.') extension = '.' + extension;
object obj;
shell.AssocCreate(shell.CLSID_QueryAssociations, ref shell.IID_IQueryAssociations, out obj);
var qa = (shell.IQueryAssociations)obj;
qa.Init(shell.ASSOCF.INIT_DEFAULTTOSTAR, Convert.ToString(extension), UIntPtr.Zero, IntPtr.Zero);
var bufSize = 0;
qa.GetString(shell.ASSOCF.NOTRUNCATE, shell.ASSOCSTR.DEFAULTICON, null, null, ref bufSize);
var sb = new StringBuilder(bufSize);
qa.GetString(shell.ASSOCF.NOTRUNCATE, shell.ASSOCSTR.DEFAULTICON, null, sb, ref bufSize);
if (!String.IsNullOrEmpty(sb.ToString()))
{
var iconLocation = sb.ToString();
var iconPath = iconLocation.Split(',');
var iIconPathNumber = iconPath.Length > 1 ? 1 : 0;
if (iconPath[iIconPathNumber] == null) iconPath[iIconPathNumber] = "0";
var large = new IntPtr[1];
var small = new IntPtr[1];
//extracts the icon from the file.
ExtractIconEx(iconPath[0],
iIconPathNumber > 0 ? Convert.ToInt16(iconPath[iIconPathNumber]) : Convert.ToInt16(0),
large,
small, 1);
return size == SystemIconSize.Large
? Icon.FromHandle(large[0])
: Icon.FromHandle(small[0]);
}
return IntPtr.Zero;
}
In addition to the above code one needs "shell" class - a wrapper of Shell API (below it is limited to AssocCreate and necessary types):
除了上面的代码之外,还需要“shell”类——shell API的包装器(以下仅局限于AssocCreate和必要类型):
using System;
using System.Runtime.InteropServices;
using System.Text;
#pragma warning disable 1591
// ReSharper disable InconsistentNaming
namespace <put_your_appropriate_namespace_here>
{
public class shell
{
[DllImport("shlwapi.dll")]
public extern static int AssocCreate(
Guid clsid,
ref Guid riid,
[MarshalAs(UnmanagedType.Interface)] out object ppv);
[Flags]
public enum ASSOCF
{
INIT_NOREMAPCLSID = 0x00000001,
INIT_BYEXENAME = 0x00000002,
OPEN_BYEXENAME = 0x00000002,
INIT_DEFAULTTOSTAR = 0x00000004,
INIT_DEFAULTTOFOLDER = 0x00000008,
NOUSERSETTINGS = 0x00000010,
NOTRUNCATE = 0x00000020,
VERIFY = 0x00000040,
REMAPRUNDLL = 0x00000080,
NOFIXUPS = 0x00000100,
IGNOREBASECLASS = 0x00000200,
INIT_IGNOREUNKNOWN = 0x00000400
}
public enum ASSOCSTR
{
COMMAND = 1,
EXECUTABLE,
FRIENDLYDOCNAME,
FRIENDLYAPPNAME,
NOOPEN,
SHELLNEWVALUE,
DDECOMMAND,
DDEIFEXEC,
DDEAPPLICATION,
DDETOPIC,
INFOTIP,
QUICKTIP,
TILEINFO,
CONTENTTYPE,
DEFAULTICON,
SHELLEXTENSION
}
public enum ASSOCKEY
{
SHELLEXECCLASS = 1,
APP,
CLASS,
BASECLASS
}
public enum ASSOCDATA
{
MSIDESCRIPTOR = 1,
NOACTIVATEHANDLER,
QUERYCLASSSTORE,
HASPERUSERASSOC,
EDITFLAGS,
VALUE
}
[Guid("c46ca590-3c3f-11d2-bee6-0000f805ca57"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
public interface IQueryAssociations
{
void Init(
[In] ASSOCF flags,
[In, MarshalAs(UnmanagedType.LPWStr)] string pszAssoc,
[In] UIntPtr hkProgid,
[In] IntPtr hwnd);
void GetString(
[In] ASSOCF flags,
[In] ASSOCSTR str,
[In, MarshalAs(UnmanagedType.LPWStr)] string pwszExtra,
[Out, MarshalAs(UnmanagedType.LPWStr)] StringBuilder pwszOut,
[In, Out] ref int pcchOut);
void GetKey(
[In] ASSOCF flags,
[In] ASSOCKEY str,
[In, MarshalAs(UnmanagedType.LPWStr)] string pwszExtra,
[Out] out UIntPtr phkeyOut);
void GetData(
[In] ASSOCF flags,
[In] ASSOCDATA data,
[In, MarshalAs(UnmanagedType.LPWStr)] string pwszExtra,
[Out, MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 4)] out byte[] pvOut,
[In, Out] ref int pcbOut);
void GetEnum(); // not used actually
}
public static Guid CLSID_QueryAssociations = new Guid("a07034fd-6caa-4954-ac3f-97a27216f98a");
public static Guid IID_IQueryAssociations = new Guid("c46ca590-3c3f-11d2-bee6-0000f805ca57");
}
}
For WPF users, who need ImageSource:
对于需要ImageSource的WPF用户:
Replace the return type from Icon to ImageSource and the return clause to:
将返回类型从图标替换为ImageSource和return子句:
var iconPtr = size == SystemIconSize.Large ? large[0] : small[0];
if (iconPtr != IntPtr.Zero)
{
return Imaging.CreateBitmapSourceFromHIcon(
iconPtr,
Int32Rect.Empty,
BitmapSizeOptions.FromEmptyOptions());
}
#1
7
Take a look at: http://mvolo.com/display-pretty-file-icons-in-your-aspnet-applications-with-iconhandler/
看一看:http://mvolo.com/display-pretty-file-icon -in-your-aspnet-application -with-iconhandler/。
It's not the cleanest solution but it works. Otherwise, try to get your hands on a library of Icons that's based on mime type or file extension.
这并不是最干净的解决方案,但确实有效。否则,请尝试使用基于mime类型或文件扩展的图标库。
#2
37
One of my old open source project include an Icon class that does exactly that, feel free to rip it, seeing the age I put this file in the public domain anyway it's just PInvoke for most part.
我的一个旧的开放源码项目包括一个图标类,它可以做到这一点,可以随意地删除它,看到我把这个文件放到公共域中的年龄,不管怎样,它只是大部分的PInvoke。
To get an icon you use for example :
为了得到一个图标,你可以使用例如:
Icon zipIcon = BlackFox.Win32.Icons.IconFromExtension(".zip", SystemIconSize.Small);
Full sample :
完整的示例:
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);
}
}
The library :
图书馆:
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
/// <summary>
/// Contains information about a file object.
/// </summary>
struct SHFILEINFO
{
/// <summary>
/// Handle to the icon that represents the file. You are responsible for
/// destroying this handle with DestroyIcon when you no longer need it.
/// </summary>
public IntPtr hIcon;
/// <summary>
/// Index of the icon image within the system image list.
/// </summary>
public IntPtr iIcon;
/// <summary>
/// Array of values that indicates the attributes of the file object.
/// For information about these values, see the IShellFolder::GetAttributesOf
/// method.
/// </summary>
public uint dwAttributes;
/// <summary>
/// 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.
/// </summary>
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)]
public string szDisplayName;
/// <summary>
/// String that describes the type of file.
/// </summary>
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 80)]
public string szTypeName;
};
[Flags]
enum FileInfoFlags : int
{
/// <summary>
/// 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.
/// </summary>
SHGFI_ICON = 0x000000100,
/// <summary>
/// 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.
/// </summary>
SHGFI_USEFILEATTRIBUTES = 0x000000010
}
/// <summary>
/// Creates an array of handles to large or small icons extracted from
/// the specified executable file, dynamic-link library (DLL), or icon
/// file.
/// </summary>
/// <param name="lpszFile">
/// Name of an executable file, DLL, or icon file from which icons will
/// be extracted.
/// </param>
/// <param name="nIconIndex">
/// <para>
/// 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.
/// </para>
/// <para>
/// If this value is �1 and <paramref name="phiconLarge"/> and
/// <paramref name="phiconSmall"/> 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.
/// </para>
/// <para>
/// Windows 95/98/Me, Windows NT 4.0 and later: If this value is a
/// negative number and either <paramref name="phiconLarge"/> or
/// <paramref name="phiconSmall"/> is not NULL, the function begins by
/// extracting the icon whose resource identifier is equal to the
/// absolute value of <paramref name="nIconIndex"/>. For example, use -3
/// to extract the icon whose resource identifier is 3.
/// </para>
/// </param>
/// <param name="phIconLarge">
/// 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.
/// </param>
/// <param name="phIconSmall">
/// 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.
/// </param>
/// <param name="nIcons">
/// Specifies the number of icons to extract from the file.
/// </param>
/// <returns>
/// If the <paramref name="nIconIndex"/> parameter is -1, the
/// <paramref name="phIconLarge"/> parameter is NULL, and the
/// <paramref name="phiconSmall"/> 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.
/// </returns>
[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
/// <summary>
/// Two constants extracted from the FileInfoFlags, the only that are
/// meaningfull for the user of this class.
/// </summary>
public enum SystemIconSize : int
{
Large = 0x000000000,
Small = 0x000000001
}
/// <summary>
/// Get the number of icons in the specified file.
/// </summary>
/// <param name="fileName">Full path of the file to look for.</param>
/// <returns></returns>
static int GetIconsCountInFile(string fileName)
{
return ExtractIconEx(fileName, -1, null, null, 0);
}
#region ExtractIcon-like functions
public static void ExtractEx(string fileName, List<Icon> largeIcons,
List<Icon> 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<Icon> ExtractEx(string fileName, SystemIconSize size,
int firstIconIndex, int iconCount)
{
List<Icon> iconList = new List<Icon>();
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<Icon> largeIcons, List<Icon> smallIcons)
{
int iconCount = GetIconsCountInFile(fileName);
ExtractEx(fileName, largeIcons, smallIcons, 0, iconCount);
}
public static List<Icon> 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<Icon> 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<Icon> smallIconList = new List<Icon>();
List<Icon> largeIconList = new List<Icon>();
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));
}
/// <summary>
/// Parse strings in registry who contains the name of the icon and
/// the index of the icon an return both parts.
/// </summary>
/// <param name="regString">The full string in the form "path,index" as found in registry.</param>
/// <param name="fileName">The "path" part of the string.</param>
/// <param name="index">The "index" part of the string.</param>
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);
}
}
}
#3
5
I'm sure you have already found a solution for your problems but for the benefit of others i have made some modifications to VirtualBlackFox's solution.
我相信你已经找到了解决问题的方法,但是为了其他人的利益,我已经对VirtualBlackFox的解决方案做了一些修改。
Just replace the IconFromExtension method...
只需替换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]);
}
#4
4
Icon.ExtractAssociatedIcon() won't do the trick. As MSDN states it only extracts icons contained in the file. So creating dummy files won't help either. To my best knowledge you have to go the p/invoke way to get to these icons. A question related to this is this. MaLio seems to have a quite complete example of how to get the icons with p/invoke.
我不会做这个魔术的。作为MSDN,它只提取文件中包含的图标。所以创建虚拟文件也无济于事。据我所知,您必须使用p/invoke方法才能到达这些图标。与此相关的一个问题是。MaLio似乎有一个非常完整的例子,说明如何使用p/invoke来获取图标。
I don't know of a platform agnostic way to do this either (and I don't think there is one).
我也不知道一个平台不可知的方法(我不认为有这样的方法)。
Sorry i couldn't provide you with better news!
对不起,我不能给你提供更好的消息!
#5
3
This class should do the job. Pass either a filename (with path) or folder name (with path).
这个类应该做这个工作。传递文件名(带有路径)或文件夹名(带有路径)。
public static class FileIcon
{
[DllImport("shell32.dll")]
private static extern IntPtr SHGetFileInfo(string pszPath, uint dwFileAttributes, ref SHFILEINFO psfi, uint cbSizeFileInfo, uint uFlags);
[StructLayout(LayoutKind.Sequential)]
private 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;
};
private const uint SHGFI_ICON = 0x100;
private const uint SHGFI_LARGEICON = 0x0; // 'Large icon
private const uint SHGFI_SMALLICON = 0x1; // 'Small icon
public static System.Drawing.Icon GetLargeIcon(string file)
{
FileIcon.SHFILEINFO shinfo = new FileIcon.SHFILEINFO();
IntPtr hImgLarge = FileIcon.SHGetFileInfo(file, 0, ref shinfo, (uint)Marshal.SizeOf(shinfo), FileIcon.SHGFI_ICON | FileIcon.SHGFI_LARGEICON);
return System.Drawing.Icon.FromHandle(shinfo.hIcon);
}
public static System.Drawing.Icon GetSmallIcon(string file)
{
FileIcon.SHFILEINFO shinfo = new FileIcon.SHFILEINFO();
IntPtr hImgLarge = FileIcon.SHGetFileInfo(file, 0, ref shinfo, (uint)Marshal.SizeOf(shinfo), FileIcon.SHGFI_ICON | FileIcon.SHGFI_SMALLICON);
return System.Drawing.Icon.FromHandle(shinfo.hIcon);
}
}
#6
3
Instead of browsing through registry, one may use the IQueryAssociations interface. This interface can also be used to get more information about registered file types (see i.e. ASSOCSTR type). Below I attach code which replaces IconFromExtension method from VirtualBlackFox's solution (parts of his code are left untouched):
与其浏览注册表,还可以使用IQueryAssociations接口。该接口还可以用于获取关于注册文件类型的更多信息(参见:ASSOCSTR类型)。下面我附上了代码,它用VirtualBlackFox的解决方案替换了IconFromExtension方法(他的代码部分未被修改):
public static Icon IconFromExtension(string extension, SystemIconSize size)
{
if (extension[0] != '.') extension = '.' + extension;
object obj;
shell.AssocCreate(shell.CLSID_QueryAssociations, ref shell.IID_IQueryAssociations, out obj);
var qa = (shell.IQueryAssociations)obj;
qa.Init(shell.ASSOCF.INIT_DEFAULTTOSTAR, Convert.ToString(extension), UIntPtr.Zero, IntPtr.Zero);
var bufSize = 0;
qa.GetString(shell.ASSOCF.NOTRUNCATE, shell.ASSOCSTR.DEFAULTICON, null, null, ref bufSize);
var sb = new StringBuilder(bufSize);
qa.GetString(shell.ASSOCF.NOTRUNCATE, shell.ASSOCSTR.DEFAULTICON, null, sb, ref bufSize);
if (!String.IsNullOrEmpty(sb.ToString()))
{
var iconLocation = sb.ToString();
var iconPath = iconLocation.Split(',');
var iIconPathNumber = iconPath.Length > 1 ? 1 : 0;
if (iconPath[iIconPathNumber] == null) iconPath[iIconPathNumber] = "0";
var large = new IntPtr[1];
var small = new IntPtr[1];
//extracts the icon from the file.
ExtractIconEx(iconPath[0],
iIconPathNumber > 0 ? Convert.ToInt16(iconPath[iIconPathNumber]) : Convert.ToInt16(0),
large,
small, 1);
return size == SystemIconSize.Large
? Icon.FromHandle(large[0])
: Icon.FromHandle(small[0]);
}
return IntPtr.Zero;
}
In addition to the above code one needs "shell" class - a wrapper of Shell API (below it is limited to AssocCreate and necessary types):
除了上面的代码之外,还需要“shell”类——shell API的包装器(以下仅局限于AssocCreate和必要类型):
using System;
using System.Runtime.InteropServices;
using System.Text;
#pragma warning disable 1591
// ReSharper disable InconsistentNaming
namespace <put_your_appropriate_namespace_here>
{
public class shell
{
[DllImport("shlwapi.dll")]
public extern static int AssocCreate(
Guid clsid,
ref Guid riid,
[MarshalAs(UnmanagedType.Interface)] out object ppv);
[Flags]
public enum ASSOCF
{
INIT_NOREMAPCLSID = 0x00000001,
INIT_BYEXENAME = 0x00000002,
OPEN_BYEXENAME = 0x00000002,
INIT_DEFAULTTOSTAR = 0x00000004,
INIT_DEFAULTTOFOLDER = 0x00000008,
NOUSERSETTINGS = 0x00000010,
NOTRUNCATE = 0x00000020,
VERIFY = 0x00000040,
REMAPRUNDLL = 0x00000080,
NOFIXUPS = 0x00000100,
IGNOREBASECLASS = 0x00000200,
INIT_IGNOREUNKNOWN = 0x00000400
}
public enum ASSOCSTR
{
COMMAND = 1,
EXECUTABLE,
FRIENDLYDOCNAME,
FRIENDLYAPPNAME,
NOOPEN,
SHELLNEWVALUE,
DDECOMMAND,
DDEIFEXEC,
DDEAPPLICATION,
DDETOPIC,
INFOTIP,
QUICKTIP,
TILEINFO,
CONTENTTYPE,
DEFAULTICON,
SHELLEXTENSION
}
public enum ASSOCKEY
{
SHELLEXECCLASS = 1,
APP,
CLASS,
BASECLASS
}
public enum ASSOCDATA
{
MSIDESCRIPTOR = 1,
NOACTIVATEHANDLER,
QUERYCLASSSTORE,
HASPERUSERASSOC,
EDITFLAGS,
VALUE
}
[Guid("c46ca590-3c3f-11d2-bee6-0000f805ca57"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
public interface IQueryAssociations
{
void Init(
[In] ASSOCF flags,
[In, MarshalAs(UnmanagedType.LPWStr)] string pszAssoc,
[In] UIntPtr hkProgid,
[In] IntPtr hwnd);
void GetString(
[In] ASSOCF flags,
[In] ASSOCSTR str,
[In, MarshalAs(UnmanagedType.LPWStr)] string pwszExtra,
[Out, MarshalAs(UnmanagedType.LPWStr)] StringBuilder pwszOut,
[In, Out] ref int pcchOut);
void GetKey(
[In] ASSOCF flags,
[In] ASSOCKEY str,
[In, MarshalAs(UnmanagedType.LPWStr)] string pwszExtra,
[Out] out UIntPtr phkeyOut);
void GetData(
[In] ASSOCF flags,
[In] ASSOCDATA data,
[In, MarshalAs(UnmanagedType.LPWStr)] string pwszExtra,
[Out, MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 4)] out byte[] pvOut,
[In, Out] ref int pcbOut);
void GetEnum(); // not used actually
}
public static Guid CLSID_QueryAssociations = new Guid("a07034fd-6caa-4954-ac3f-97a27216f98a");
public static Guid IID_IQueryAssociations = new Guid("c46ca590-3c3f-11d2-bee6-0000f805ca57");
}
}
For WPF users, who need ImageSource:
对于需要ImageSource的WPF用户:
Replace the return type from Icon to ImageSource and the return clause to:
将返回类型从图标替换为ImageSource和return子句:
var iconPtr = size == SystemIconSize.Large ? large[0] : small[0];
if (iconPtr != IntPtr.Zero)
{
return Imaging.CreateBitmapSourceFromHIcon(
iconPtr,
Int32Rect.Empty,
BitmapSizeOptions.FromEmptyOptions());
}