Files
DeskCore/ShellIcon.cs
T
M_ViperandClaude Opus 5.5 77bb3e6b9d DeskCore 1.0.0
Desktop-Icons in eigene Kategorien sortieren: Windows-11-Design (hell/dunkel),
Desktop-Boxen, automatisches Einsortieren nach Regeln, Rückgängig, Suche,
Infobereich mit Tastenkürzel, Sicherung als ZIP und Installer ohne Adminrechte.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-01 20:19:32 +02:00

101 lines
3.6 KiB
C#

using System.Runtime.InteropServices;
using System.Windows.Media;
using System.Windows.Media.Imaging;
namespace DeskCore;
/// <summary>Holt das Icon (bzw. Vorschaubild) einer Datei so, wie der Explorer es anzeigt.</summary>
public static class ShellIcon
{
public static ImageSource? Get(string path, int size = 64)
{
IntPtr hbm = IntPtr.Zero;
try
{
SHCreateItemFromParsingName(path, IntPtr.Zero, typeof(IShellItemImageFactory).GUID, out var factory);
int hr = factory.GetImage(new SIZE { cx = size, cy = size }, 0, out hbm);
Marshal.ReleaseComObject(factory);
if (hr != 0 || hbm == IntPtr.Zero) return null;
return FromHBitmap(hbm);
}
catch
{
return null;
}
finally
{
if (hbm != IntPtr.Zero) DeleteObject(hbm);
}
}
// CreateBitmapSourceFromHBitmap verliert den Alphakanal, daher Pixel selbst kopieren.
private static BitmapSource? FromHBitmap(IntPtr hbm)
{
GetObject(hbm, Marshal.SizeOf<BITMAP>(), out BITMAP bm);
int w = bm.bmWidth, h = Math.Abs(bm.bmHeight);
if (w <= 0 || h <= 0) return null;
var bmi = new BITMAPINFOHEADER
{
biSize = Marshal.SizeOf<BITMAPINFOHEADER>(),
biWidth = w,
biHeight = -h, // top-down
biPlanes = 1,
biBitCount = 32,
};
var bits = new byte[w * h * 4];
IntPtr hdc = GetDC(IntPtr.Zero);
try
{
if (GetDIBits(hdc, hbm, 0, (uint)h, bits, ref bmi, 0) == 0) return null;
}
finally
{
ReleaseDC(IntPtr.Zero, hdc);
}
bool hasAlpha = false;
for (int i = 3; i < bits.Length; i += 4)
if (bits[i] != 0) { hasAlpha = true; break; }
var src = BitmapSource.Create(w, h, 96, 96, hasAlpha ? PixelFormats.Pbgra32 : PixelFormats.Bgr32, null, bits, w * 4);
src.Freeze();
return src;
}
[ComImport, Guid("bcc18b79-ba16-442f-80c4-8a59c30c463b"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
private interface IShellItemImageFactory
{
[PreserveSig] int GetImage(SIZE size, int flags, out IntPtr phbm);
}
[StructLayout(LayoutKind.Sequential)]
private struct SIZE { public int cx, cy; }
[StructLayout(LayoutKind.Sequential)]
private struct BITMAP
{
public int bmType, bmWidth, bmHeight, bmWidthBytes;
public ushort bmPlanes, bmBitsPixel;
public IntPtr bmBits;
}
[StructLayout(LayoutKind.Sequential)]
private struct BITMAPINFOHEADER
{
public int biSize, biWidth, biHeight;
public ushort biPlanes, biBitCount;
public int biCompression, biSizeImage, biXPelsPerMeter, biYPelsPerMeter, biClrUsed, biClrImportant;
}
[DllImport("shell32.dll", CharSet = CharSet.Unicode, PreserveSig = false)]
private static extern void SHCreateItemFromParsingName(string path, IntPtr pbc,
[MarshalAs(UnmanagedType.LPStruct)] Guid riid, out IShellItemImageFactory ppv);
[DllImport("gdi32.dll")] private static extern bool DeleteObject(IntPtr h);
[DllImport("gdi32.dll")] private static extern int GetObject(IntPtr h, int size, out BITMAP bm);
[DllImport("gdi32.dll")] private static extern int GetDIBits(IntPtr hdc, IntPtr hbm, uint start, uint lines, byte[] bits, ref BITMAPINFOHEADER bmi, uint usage);
[DllImport("user32.dll")] private static extern IntPtr GetDC(IntPtr hwnd);
[DllImport("user32.dll")] private static extern int ReleaseDC(IntPtr hwnd, IntPtr hdc);
}