Files
Taskbar-Launcher/Services/IconService.cs
2026-06-02 17:28:25 -04:00

128 lines
4.0 KiB
C#

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<ShFileInfo>(), 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;
}
}