130 lines
4.1 KiB
C#
130 lines
4.1 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;
|
|
}
|
|
|
|
path = Environment.ExpandEnvironmentVariables(path);
|
|
|
|
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;
|
|
}
|
|
}
|