c# - studio - png to ico
Obtener el icono de archivo utilizado por Shell (9)
¡Ignore a todos los que le digan que use el registro! El registro NO ES UNA API. La API que desea es SHGetFileInfo con SHGFI_ICON. Puede obtener una firma de P / Invoke aquí:
En .Net (C # o VB: no me importa), dada una cadena de ruta de archivo, estructura de FileInfo o estructura de FileSystemInfo para un archivo real existente, ¿cómo puedo determinar los íconos utilizados por el shell (explorador) para ese ¿archivo?
Actualmente no estoy planeando usar esto para nada, pero sentí curiosidad acerca de cómo hacerlo al mirar esta pregunta y pensé que sería útil tener archivado aquí en SO.
Debería usar SHGetFileInfo.
Icon.ExtractAssociatedIcon funciona tan bien como SHGetFileInfo en la mayoría de los casos, pero SHGetFileInfo puede funcionar con rutas UNC (por ejemplo, una ruta de red como "// ComputerName / SharedFolder /") mientras que Icon.ExtractAssociatedIcon no puede hacerlo. Si necesita o podría necesitar utilizar rutas UNC, sería mejor utilizar SHGetFileInfo en lugar de Icon.ExtractAssociatedIcon.
Este es un buen artículo de CodeProject sobre cómo usar SHGetFileInfo.
El problema con el enfoque de registro es que no obtiene explícitamente el ícono de identificación del índice. Algunas veces (si no todas las veces), obtienes un ícono ResourceID que es un alias que el desarrollador de la aplicación usó para nombrar el espacio del ícono.
Por lo tanto, el método de registro implica que todos los desarrolladores utilicen ResourceID, que son los mismos que el ícono del ícono índico (que es cero, absoluto, determinista).
Escanee la ubicación del registro y verá muchos números negativos, a veces incluso referencias de texto, es decir, no la id del índice del icono. Un método implícito parece mejor, ya que permite que el SO haga el trabajo.
Solo estoy probando este nuevo método ahora pero tiene sentido y con suerte resuelve este problema.
Esto funciona para mí en mis proyectos, espero que esto ayude a alguien.
Es C # con P / Invoca que funcionará hasta ahora en sistemas x86 / x64 desde WinXP.
(Shell.cs)
using System;
using System.Drawing;
using System.IO;
using System.Runtime.InteropServices;
namespace IconExtraction
{
internal sealed class Shell : NativeMethods
{
#region OfExtension
///<summary>
/// Get the icon of an extension
///</summary>
///<param name="filename">filename</param>
///<param name="overlay">bool symlink overlay</param>
///<returns>Icon</returns>
public static Icon OfExtension(string filename, bool overlay = false)
{
string filepath;
string[] extension = filename.Split(''.'');
string dirpath = Path.Combine(System.AppDomain.CurrentDomain.BaseDirectory, "cache");
Directory.CreateDirectory(dirpath);
if (String.IsNullOrEmpty(filename) || extension.Length == 1)
{
filepath = Path.Combine(dirpath, "dummy_file");
}
else
{
filepath = Path.Combine(dirpath, String.Join(".", "dummy", extension[extension.Length - 1]));
}
if (File.Exists(filepath) == false)
{
File.Create(filepath);
}
Icon icon = OfPath(filepath, true, true, overlay);
return icon;
}
#endregion
#region OfFolder
///<summary>
/// Get the icon of an extension
///</summary>
///<returns>Icon</returns>
///<param name="overlay">bool symlink overlay</param>
public static Icon OfFolder(bool overlay = false)
{
string dirpath = Path.Combine(System.AppDomain.CurrentDomain.BaseDirectory, "cache", "dummy");
Directory.CreateDirectory(dirpath);
Icon icon = OfPath(dirpath, true, true, overlay);
return icon;
}
#endregion
#region OfPath
///<summary>
/// Get the normal,small assigned icon of the given path
///</summary>
///<param name="filepath">physical path</param>
///<param name="small">bool small icon</param>
///<param name="checkdisk">bool fileicon</param>
///<param name="overlay">bool symlink overlay</param>
///<returns>Icon</returns>
public static Icon OfPath(string filepath, bool small = true, bool checkdisk = true, bool overlay = false)
{
Icon clone;
SHGFI_Flag flags;
SHFILEINFO shinfo = new SHFILEINFO();
if (small)
{
flags = SHGFI_Flag.SHGFI_ICON | SHGFI_Flag.SHGFI_SMALLICON;
}
else
{
flags = SHGFI_Flag.SHGFI_ICON | SHGFI_Flag.SHGFI_LARGEICON;
}
if (checkdisk == false)
{
flags |= SHGFI_Flag.SHGFI_USEFILEATTRIBUTES;
}
if (overlay)
{
flags |= SHGFI_Flag.SHGFI_LINKOVERLAY;
}
if (SHGetFileInfo(filepath, 0, ref shinfo, Marshal.SizeOf(shinfo), flags) == 0)
{
throw (new FileNotFoundException());
}
Icon tmp = Icon.FromHandle(shinfo.hIcon);
clone = (Icon)tmp.Clone();
tmp.Dispose();
if (DestroyIcon(shinfo.hIcon) != 0)
{
return clone;
}
return clone;
}
#endregion
}
}
(NativeMethods.cs)
using System;
using System.Drawing;
using System.Runtime.InteropServices;
namespace IconExtraction
{
internal class NativeMethods
{
public struct SHFILEINFO
{
public IntPtr hIcon;
public int iIcon;
public uint dwAttributes;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)]
public string szDisplayName;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 80)]
public string szTypeName;
};
[DllImport("user32.dll")]
public static extern int DestroyIcon(IntPtr hIcon);
[DllImport("shell32.dll", CharSet = CharSet.Auto, BestFitMapping = false, ThrowOnUnmappableChar = true)]
public static extern IntPtr ExtractIcon(IntPtr hInst, string lpszExeFileName, int nIconIndex);
[DllImport("Shell32.dll", BestFitMapping = false, ThrowOnUnmappableChar = true)]
public static extern int SHGetFileInfo(string pszPath, int dwFileAttributes, ref SHFILEINFO psfi, int cbFileInfo, SHGFI_Flag uFlags);
[DllImport("Shell32.dll")]
public static extern int SHGetFileInfo(IntPtr pszPath, uint dwFileAttributes, ref SHFILEINFO psfi, int cbFileInfo, SHGFI_Flag uFlags);
}
public enum SHGFI_Flag : uint
{
SHGFI_ATTR_SPECIFIED = 0x000020000,
SHGFI_OPENICON = 0x000000002,
SHGFI_USEFILEATTRIBUTES = 0x000000010,
SHGFI_ADDOVERLAYS = 0x000000020,
SHGFI_DISPLAYNAME = 0x000000200,
SHGFI_EXETYPE = 0x000002000,
SHGFI_ICON = 0x000000100,
SHGFI_ICONLOCATION = 0x000001000,
SHGFI_LARGEICON = 0x000000000,
SHGFI_SMALLICON = 0x000000001,
SHGFI_SHELLICONSIZE = 0x000000004,
SHGFI_LINKOVERLAY = 0x000008000,
SHGFI_SYSICONINDEX = 0x000004000,
SHGFI_TYPENAME = 0x000000400
}
}
Nada más que una versión C # de la respuesta de Stefan.
using System.Drawing;
class Class1
{
public static void Main()
{
var filePath = @"C:/myfile.exe";
var theIcon = IconFromFilePath(filePath);
if (theIcon != null)
{
// Save it to disk, or do whatever you want with it.
using (var stream = new System.IO.FileStream(@"c:/myfile.ico", System.IO.FileMode.CreateNew))
{
theIcon.Save(stream);
}
}
}
public static Icon IconFromFilePath(string filePath)
{
var result = (Icon)null;
try
{
result = Icon.ExtractAssociatedIcon(filePath);
}
catch (System.Exception)
{
// swallow and return nothing. You could supply a default Icon here as well
}
return result;
}
}
Si solo está interesado en un icono para una extensión específica y si no le importa crear un archivo temporal, puede seguir el ejemplo que se muestra here
C # code:
public Icon LoadIconFromExtension(string extension)
{
string path = string.Format("dummy{0}", extension);
using (File.Create(path)) { }
Icon icon = Icon.ExtractAssociatedIcon(path);
File.Delete(path);
return icon;
}
This enlace parece tener algo de información. Implica una gran cantidad de registros atravesados, pero parece factible. Los ejemplos están en C ++
Imports System.Drawing
Module Module1
Sub Main()
Dim filePath As String = "C:/myfile.exe"
Dim TheIcon As Icon = IconFromFilePath(filePath)
If TheIcon IsNot Nothing Then
''''#Save it to disk, or do whatever you want with it.
Using stream As New System.IO.FileStream("c:/myfile.ico", IO.FileMode.CreateNew)
TheIcon.Save(stream)
End Using
End If
End Sub
Public Function IconFromFilePath(filePath As String) As Icon
Dim result As Icon = Nothing
Try
result = Icon.ExtractAssociatedIcon(filePath)
Catch ''''# swallow and return nothing. You could supply a default Icon here as well
End Try
Return result
End Function
End Module
- determinar la extensión
- en el registro, vaya a
"HKCR/.{extension}"
, lea el valor predeterminado (vamos a llamarlofiletype
) - en
"HKCR/{filetype}/DefaultIcon"
, lea el valor predeterminado: esta es la ruta al archivo de icono (o archivo de contenedor de icono, como un .exe con un recurso de icono incrustado) - si es necesario, use su método preferido para extraer el recurso del icono del archivo mencionado
edit / movido desde los comentarios:
Si el icono está en un archivo contenedor (esto es bastante común), habrá un contador después de la ruta, como este: "foo.exe,3"
. Esto significa que es el ícono número 4 (el índice está basado en cero) de los íconos disponibles. Un valor de ", 0" es implícito (y opcional). Si el contador es 0 o falta, el icono disponible del puño será utilizado por el shell.