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>
101 lines
3.6 KiB
C#
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);
|
|
}
|