using System.Drawing; using System.IO; using System.Runtime.InteropServices; using System.Windows; using System.Windows.Interop; using System.Windows.Media; using System.Windows.Media.Imaging; using TaskbarLauncher.Models; namespace TaskbarLauncher.Services; public static class IconService { private const uint ShgfiIcon = 0x000000100; private const uint ShgfiLargeIcon = 0x000000000; private const uint ShgfiSmallIcon = 0x000000001; private const uint ShgfiUseFileAttributes = 0x000000010; private const uint FileAttributeDirectory = 0x00000010; private const uint FileAttributeNormal = 0x00000080; public static ImageSource? GetIcon(LauncherItem item, bool large) { ImageSource? explicitIcon = TryLoadIcon(item.IconPath, large, useAttributes: false); if (explicitIcon is not null) { return explicitIcon; } if (!string.IsNullOrWhiteSpace(item.Target)) { ImageSource? targetIcon = TryLoadIcon(item.Target, large, useAttributes: false); if (targetIcon is not null) { return targetIcon; } } return item.Type switch { LauncherItemType.Folder => TryLoadIcon("folder", large, useAttributes: true, isDirectory: true), LauncherItemType.Website => TryLoadIcon(".url", large, useAttributes: true), LauncherItemType.File => TryLoadIcon(".txt", large, useAttributes: true), LauncherItemType.Menu => TryLoadIcon("folder", large, useAttributes: true, isDirectory: true), _ => TryLoadIcon(".exe", large, useAttributes: true) }; } private static ImageSource? TryLoadIcon(string? path, bool large, bool useAttributes, bool isDirectory = false) { if (string.IsNullOrWhiteSpace(path)) { return null; } try { uint flags = ShgfiIcon | (large ? ShgfiLargeIcon : ShgfiSmallIcon); uint attributes = isDirectory ? FileAttributeDirectory : FileAttributeNormal; if (useAttributes) { flags |= ShgfiUseFileAttributes; } IntPtr result = SHGetFileInfo(path, attributes, out ShFileInfo fileInfo, (uint)Marshal.SizeOf(), flags); if (result == IntPtr.Zero || fileInfo.IconHandle == IntPtr.Zero) { return null; } ImageSource image = Imaging.CreateBitmapSourceFromHIcon( fileInfo.IconHandle, Int32Rect.Empty, BitmapSizeOptions.FromEmptyOptions()); image.Freeze(); DestroyIcon(fileInfo.IconHandle); return image; } catch { try { using Icon? icon = File.Exists(path) ? Icon.ExtractAssociatedIcon(path) : null; if (icon is null) { return null; } ImageSource image = Imaging.CreateBitmapSourceFromHIcon( icon.Handle, Int32Rect.Empty, BitmapSizeOptions.FromEmptyOptions()); image.Freeze(); return image; } catch { return null; } } } [DllImport("shell32.dll", CharSet = CharSet.Unicode)] private static extern IntPtr SHGetFileInfo( string path, uint fileAttributes, out ShFileInfo fileInfo, uint fileInfoSize, uint flags); [DllImport("user32.dll", SetLastError = true)] private static extern bool DestroyIcon(IntPtr icon); [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] private struct ShFileInfo { public IntPtr IconHandle; public int IconIndex; public uint Attributes; [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)] public string DisplayName; [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 80)] public string TypeName; } }