IconHelper.cs
using System.Runtime.InteropServices;
using System.Windows;
using System.Windows.Interop;
using System.Windows.Media;
using System.Windows.Media.Imaging;
namespace Maywork.WPF.Helpers;
public static class IconHelper
{
// ------------------------------------------------------------
// Win32 API
// ------------------------------------------------------------
[DllImport("Shell32.dll", CharSet = CharSet.Unicode)]
private static extern IntPtr SHGetFileInfo(
string pszPath,
uint dwFileAttributes,
out SHFILEINFO psfi,
uint cbFileInfo,
uint uFlags);
[DllImport("Shell32.dll", EntryPoint = "#727")]
private static extern int SHGetImageList(
int iImageList,
ref Guid riid,
out IImageList ppv);
[DllImport("User32.dll", SetLastError = true)]
private static extern bool DestroyIcon(IntPtr hIcon);
// ------------------------------------------------------------
// Structs & Constants
// ------------------------------------------------------------
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
private 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;
}
private const uint SHGFI_SYSICONINDEX = 0x00004000;
private const uint SHGFI_USEFILEATTRIBUTES = 0x000000010;
private const uint FILE_ATTRIBUTE_DIRECTORY = 0x00000010;
private const uint FILE_ATTRIBUTE_NORMAL = 0x00000080;
private const int SHIL_SMALL = 0; // 16x16
private const int SHIL_LARGE = 1; // 32x32
private const int SHIL_EXTRALARGE = 2; // 48x48
private const int SHIL_JUMBO = 4; // 256x256
// ------------------------------------------------------------
// COM Interface (Order is critical!)
// ------------------------------------------------------------
[ComImport]
[Guid("46EB5926-582E-4017-9FDF-E8998DAA0950")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
private interface IImageList
{
int Add(IntPtr hbmImage, IntPtr hbmMask, ref int pi);
int ReplaceIcon(int i, IntPtr hicon, ref int pi);
int SetOverlayImage(int iImage, int iOverlay);
int Replace(int i, IntPtr hbmImage, IntPtr hbmMask);
int AddMasked(IntPtr hbmImage, uint crMask, ref int pi);
int Draw(IntPtr pimldp); // 引数は簡易化
int Remove(int i);
int GetIcon(int i, int flags, out IntPtr picon); // 8番目のメソッド
// 以降のメソッドは今回使用しないため省略可能
}
// ------------------------------------------------------------
// Public API
// ------------------------------------------------------------
public static ImageSource GetIconImageSource(string path, int size = 32)
{
var info = new SHFILEINFO();
bool isDirectory = System.IO.Directory.Exists(path);
uint attr = isDirectory ? (uint)0x10 : (uint)0x80; // 0x10: Directory, 0x80: Normal File
uint flags = SHGFI_SYSICONINDEX | SHGFI_USEFILEATTRIBUTES;
// 第一引数に path を渡しても、USEFILEATTRIBUTES があれば属性優先になります。
SHGetFileInfo(path, attr, out info, (uint)Marshal.SizeOf(info), flags);
// 2. サイズに応じたイメージリストの種類を選択
int listType = size switch
{
<= 16 => SHIL_SMALL,
<= 32 => SHIL_LARGE,
<= 48 => SHIL_EXTRALARGE,
_ => SHIL_JUMBO
};
// 3. IImageList 取得
Guid guid = typeof(IImageList).GUID;
int hr = SHGetImageList(listType, ref guid, out var imageList);
if (hr == 0 && imageList != null)
{
hr = imageList.GetIcon(info.iIcon, 0x00000001, out IntPtr hIcon);
if (hr == 0 && hIcon != IntPtr.Zero)
{
try
{
// BitmapSizeOptions を指定せず、元のサイズを維持して作成
var bmp = Imaging.CreateBitmapSourceFromHIcon(
hIcon,
Int32Rect.Empty,
BitmapSizeOptions.FromEmptyOptions());
bmp.Freeze();
return bmp;
}
finally
{
DestroyIcon(hIcon); // ハンドル漏れ防止
}
}
}
// 何も取れなければ透明1x1
var wb = new WriteableBitmap(1, 1, 96, 96, PixelFormats.Bgra32, null);
wb.Freeze();
return wb;
}
}
/*
public static class IconHelper
{
// SHGetFileInfoでHICONを取得してWPFのImageSourceへ変換
[DllImport("Shell32.dll", CharSet = CharSet.Unicode)]
private static extern IntPtr SHGetFileInfo(string pszPath, uint dwFileAttributes,
out SHFILEINFO psfi, uint cbFileInfo, uint uFlags);
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
private 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;
}
private const uint SHGFI_ICON = 0x000000100;
private const uint SHGFI_LARGEICON = 0x000000000; // 32x32
private const uint SHGFI_SHELLICONSIZE = 0x000000004;
[DllImport("User32.dll", SetLastError = true)]
private static extern bool DestroyIcon(IntPtr hIcon);
public static ImageSource GetIconImageSource(string path)
{
var info = new SHFILEINFO();
IntPtr result = SHGetFileInfo(path, 0, out info, (uint)Marshal.SizeOf(info),
SHGFI_ICON | SHGFI_LARGEICON | SHGFI_SHELLICONSIZE);
if (result != IntPtr.Zero && info.hIcon != IntPtr.Zero)
{
var img = Imaging.CreateBitmapSourceFromHIcon(
info.hIcon, Int32Rect.Empty, BitmapSizeOptions.FromEmptyOptions());
DestroyIcon(info.hIcon);
img.Freeze();
return img;
}
// 何も取れなければ透明1x1
var wb = new WriteableBitmap(1, 1, 96, 96, PixelFormats.Bgra32, null);
wb.Freeze();
return wb;
}
}
*/
Download

コメント