.Net(C#またはVB:do n't care)で、実際の既存ファイルのファイルパス文字列、FileInfo構造体、またはFileSystemInfo構造体を指定すると、そのシェル(エクスプローラー)が使用するアイコンをどのように判断できますかファイル?
私は現在これを何かに使うつもりはありませんが、 この質問 を見たときにどうするか興味があり、SOでここにアーカイブしておくと便利だと思いました。
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
レジストリを使用するように言っているすべての人を無視してください!レジストリはAPIではありません。必要なAPIは、SHGFI_ICONを使用したSHGetFileInfoです。ここでP/Invoke署名を取得できます。
SHGetFileInfoを使用する必要があります。
Icon.ExtractAssociatedIconはほとんどの場合SHGetFileInfoと同じように機能しますが、SHGetFileInfoはUNCパス(たとえば、「\\ ComputerName\SharedFolder \」などのネットワークパス)で機能しますが、Icon.ExtractAssociatedIconは機能しません。 UNCパスを使用する必要がある場合、または使用する必要がある場合は、Icon.ExtractAssociatedIconではなくSHGetFileInfoを使用することをお勧めします。
これはCodeProjectの優れた記事です SHGetFileInfoの使用方法について。
Stefanの回答のC#バージョンにすぎません。
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;
}
}
これは私のプロジェクトでうまくいきます。これが誰かの助けになることを願っています。
P/Invokesを使用したC#であり、WinXP以降、x86/x64システムで動作します。
(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
}
}
レジストリアプローチの問題は、アイコンインデックスIDを明示的に取得していないことです。時々(常にではありませんが)、アイコンResourceIDを取得します。これは、アプリケーション開発者がアイコンのスロットに名前を付けるために使用したエイリアスです。
したがって、レジストリメソッドは、すべての開発者が暗黙的なアイコンインデックスID(ゼロベース、絶対、決定論的)と同じResourceIDを使用することを意味します。
レジストリの場所をスキャンすると、多くの負の数、場合によってはテキスト参照さえも表示されます。つまり、アイコンインデックスIDではありません。暗黙的な方法は、OSが作業を実行できるため、より良いようです。
現在この新しいメソッドをテストするだけですが、理にかなっており、うまくいけばこの問題を解決できます。
特定の拡張子のアイコンにのみ興味があり、一時ファイルの作成を気にしない場合は、表示される例に従ってください here
C#コード:
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;
}
これ リンクには情報があるようです。多くのレジストリトラバースが含まれますが、実行可能と思われます。例はC++です。
"HKCR\.{extension}"
、デフォルト値を読み取ります(filetype
と呼びましょう)"HKCR\{filetype}\DefaultIcon"
、デフォルト値を読み取ります。これは、アイコンファイル(または、アイコンリソースが埋め込まれた.exeなどのアイコンコンテナファイル)へのパスです。編集/コメントから移動:
アイコンがコンテナファイルにある場合(これは非常に一般的です)、次のように、パスの後にカウンターがあります:"foo.exe,3"
。これは、使用可能なアイコンのアイコン番号4(インデックスはゼロベース)であることを意味します。 「、0」の値は暗黙的(およびオプション)です。カウンターが0または欠落している場合、利用可能な最初のアイコンがシェルによって使用されます。