-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathIconUtilities.cs
More file actions
99 lines (86 loc) · 3.4 KB
/
Copy pathIconUtilities.cs
File metadata and controls
99 lines (86 loc) · 3.4 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
using System;
using System.Collections.Concurrent;
using System.IO;
using System.Runtime.InteropServices;
using System.Windows;
using System.Windows.Interop;
using System.Windows.Media;
using System.Windows.Media.Imaging;
namespace Community.PowerToys.Run.Plugin.DiskAnalyzer
{
public static class IconUtilities
{
[StructLayout(LayoutKind.Sequential)]
public struct SHFILEINFO
{
public IntPtr hIcon;
public int iIcon;
public uint dwAttributes;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)]
public string szDisplayName;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 80)]
public string szTypeName;
}
public const uint SHGFI_ICON = 0x100;
public const uint SHGFI_SMALLICON = 0x1;
public const uint SHGFI_USEFILEATTRIBUTES = 0x10;
[DllImport("shell32.dll", CharSet = CharSet.Unicode)]
public static extern IntPtr SHGetFileInfo(string pszPath, uint dwFileAttributes, ref SHFILEINFO psfi, uint cbSizeFileInfo, uint uFlags);
[DllImport("user32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool DestroyIcon(IntPtr hIcon);
private static readonly ConcurrentDictionary<string, ImageSource?> _iconCache = new(StringComparer.OrdinalIgnoreCase);
public static ImageSource? GetIcon(string path, bool isFolder = false)
{
// Cache by extension for files, and by path for drives/folders
string cacheKey = path;
if (!isFolder && !string.IsNullOrEmpty(path))
{
cacheKey = Path.GetExtension(path);
if (string.IsNullOrEmpty(cacheKey))
cacheKey = "FILE";
}
else if (isFolder && path.Length > 3)
{
// Generic folder cache to avoid querying every folder
cacheKey = "FOLDER";
}
if (_iconCache.TryGetValue(cacheKey, out ImageSource? cachedIcon))
{
return cachedIcon;
}
uint flags = SHGFI_ICON | SHGFI_SMALLICON;
uint attributes = 0;
// For generic files/folders, use attributes so we don't hit the disk
if (cacheKey == "FOLDER" || (!isFolder && cacheKey.StartsWith(".")))
{
flags |= SHGFI_USEFILEATTRIBUTES;
attributes = isFolder ? 0x10u : 0x80u; // FILE_ATTRIBUTE_DIRECTORY or FILE_ATTRIBUTE_NORMAL
}
SHFILEINFO shfi = new SHFILEINFO();
IntPtr res = SHGetFileInfo(path, attributes, ref shfi, (uint)Marshal.SizeOf(shfi), flags);
if (res != IntPtr.Zero && shfi.hIcon != IntPtr.Zero)
{
try
{
var bitmap = Imaging.CreateBitmapSourceFromHIcon(
shfi.hIcon,
Int32Rect.Empty,
BitmapSizeOptions.FromEmptyOptions());
bitmap.Freeze();
_iconCache[cacheKey] = bitmap;
return bitmap;
}
catch
{
return null;
}
finally
{
DestroyIcon(shfi.hIcon);
}
}
return null;
}
}
}