[Feature] Show icons of *.ico files and links to *.ico files (#396), version 1.2.9.16

This commit is contained in:
Markus Hofknecht 2022-06-09 19:55:13 +02:00
parent e5e1f848e4
commit 532716ea12
9 changed files with 71 additions and 152 deletions

View file

@ -470,7 +470,7 @@ namespace SystemTrayMenu.Business
RowData rowData = ReadRowData(directory, false, true); RowData rowData = ReadRowData(directory, false, true);
rowData.HiddenEntry = hiddenEntry; rowData.HiddenEntry = hiddenEntry;
string resolvedLnkPath = string.Empty; string resolvedLnkPath = string.Empty;
rowData.ReadIcon(true, ref resolvedLnkPath, level); rowData.ReadIconOrResolveLinkAndReadIcon(true, ref resolvedLnkPath, level);
rowData.MenuLevel = level; rowData.MenuLevel = level;
menuData.RowDatas.Add(rowData); menuData.RowDatas.Add(rowData);
} }
@ -528,7 +528,7 @@ namespace SystemTrayMenu.Business
} }
string resolvedLnkPath = string.Empty; string resolvedLnkPath = string.Empty;
if (rowData.ReadIcon(false, ref resolvedLnkPath, level)) if (rowData.ReadIconOrResolveLinkAndReadIcon(false, ref resolvedLnkPath, level))
{ {
rowData = ReadRowData(resolvedLnkPath, true, true, rowData); rowData = ReadRowData(resolvedLnkPath, true, true, rowData);
rowData.HiddenEntry = hiddenEntry; rowData.HiddenEntry = hiddenEntry;

View file

@ -19,7 +19,7 @@ namespace SystemTrayMenu
{ {
private static readonly Icon SystemTrayMenu = Properties.Resources.SystemTrayMenu; private static readonly Icon SystemTrayMenu = Properties.Resources.SystemTrayMenu;
private static readonly Icon IconFromRootFolder = IconReader.GetIconSTA( private static readonly Icon IconFromRootFolder = IconReader.GetIconSTA(
Path, false, IconReader.IconSize.Small, IconReader.FolderType.Closed); Path, Path, false, IconReader.IconSize.Small, IconReader.FolderType.Closed);
private static bool readDarkModeDone; private static bool readDarkModeDone;
private static bool isDarkMode; private static bool isDarkMode;

View file

@ -81,7 +81,7 @@ namespace SystemTrayMenu.DataClasses
row[2] = data; row[2] = data;
} }
internal bool ReadIcon(bool isDirectory, ref string resolvedLnkPath, int level) internal bool ReadIconOrResolveLinkAndReadIcon(bool isDirectory, ref string resolvedLnkPath, int level)
{ {
bool isLnkDirectory = false; bool isLnkDirectory = false;
@ -108,7 +108,7 @@ namespace SystemTrayMenu.DataClasses
if (fileExtension.Equals(".lnk", StringComparison.InvariantCultureIgnoreCase)) if (fileExtension.Equals(".lnk", StringComparison.InvariantCultureIgnoreCase))
{ {
handled = SetLnk(level, ref isLnkDirectory, ref resolvedLnkPath); handled = ResolveLinkAndReadIcon(level, ref isLnkDirectory, ref resolvedLnkPath);
showOverlay = Properties.Settings.Default.ShowLinkOverlay; showOverlay = Properties.Settings.Default.ShowLinkOverlay;
} }
else if (fileExtension.Equals(".url", StringComparison.InvariantCultureIgnoreCase)) else if (fileExtension.Equals(".url", StringComparison.InvariantCultureIgnoreCase))
@ -116,10 +116,6 @@ namespace SystemTrayMenu.DataClasses
SetText($"{FileInfo.Name[0..^4]}"); SetText($"{FileInfo.Name[0..^4]}");
showOverlay = Properties.Settings.Default.ShowLinkOverlay; showOverlay = Properties.Settings.Default.ShowLinkOverlay;
} }
else if (fileExtension.Equals(".sln", StringComparison.InvariantCultureIgnoreCase))
{
handled = SetSln(level);
}
else if (fileExtension.Equals(".appref-ms", StringComparison.InvariantCultureIgnoreCase)) else if (fileExtension.Equals(".appref-ms", StringComparison.InvariantCultureIgnoreCase))
{ {
showOverlay = Properties.Settings.Default.ShowLinkOverlay; showOverlay = Properties.Settings.Default.ShowLinkOverlay;
@ -127,21 +123,14 @@ namespace SystemTrayMenu.DataClasses
if (!handled) if (!handled)
{ {
try icon = IconReader.GetFileIconWithCache(
{ TargetFilePathOrig,
FilePathIcon = TargetFilePathOrig; TargetFilePath,
icon = IconReader.GetFileIconWithCache( showOverlay,
FilePathIcon, true,
showOverlay, level == 0,
true, out bool loading);
level == 0, IconLoading = loading;
out bool loading);
IconLoading = loading;
}
catch (Exception ex)
{
Log.Warn($"path:'{TargetFilePathOrig}'", ex);
}
} }
} }
@ -250,20 +239,15 @@ namespace SystemTrayMenu.DataClasses
else else
{ {
bool showOverlay = false; bool showOverlay = false;
string fileExtension = Path.GetExtension(TargetFilePath); string fileExtension = Path.GetExtension(TargetFilePathOrig);
if (fileExtension == ".lnk" || fileExtension == ".url" || fileExtension == ".appref-ms") if (fileExtension == ".lnk" || fileExtension == ".url" || fileExtension == ".appref-ms")
{ {
showOverlay = Properties.Settings.Default.ShowLinkOverlay; showOverlay = Properties.Settings.Default.ShowLinkOverlay;
} }
string filePath = FilePathIcon;
if (string.IsNullOrEmpty(filePath))
{
filePath = TargetFilePathOrig;
}
icon = IconReader.GetFileIconWithCache( icon = IconReader.GetFileIconWithCache(
filePath, TargetFilePathOrig,
TargetFilePath,
showOverlay, showOverlay,
false, false,
MenuLevel == 0, MenuLevel == 0,
@ -299,7 +283,7 @@ namespace SystemTrayMenu.DataClasses
} }
} }
private bool SetLnk(int level, ref bool isLnkDirectory, ref string resolvedLnkPath) private bool ResolveLinkAndReadIcon(int level, ref bool isLnkDirectory, ref string resolvedLnkPath)
{ {
bool handled = false; bool handled = false;
resolvedLnkPath = FileLnk.GetResolvedFileName(TargetFilePath, out bool isFolder); resolvedLnkPath = FileLnk.GetResolvedFileName(TargetFilePath, out bool isFolder);
@ -334,26 +318,5 @@ namespace SystemTrayMenu.DataClasses
return handled; return handled;
} }
private bool SetSln(int level)
{
bool handled = false;
try
{
icon = IconReader.GetExtractAllIconsLastWithCache(
TargetFilePathOrig,
true,
level == 0,
out bool loading);
IconLoading = loading;
handled = true;
}
catch (Exception ex)
{
Log.Warn($"path:'{TargetFilePath}'", ex);
}
return handled;
}
} }
} }

View file

@ -39,5 +39,5 @@ using System.Runtime.InteropServices;
// You can specify all the values or you can default the Build and Revision Numbers // You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below: // by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")] // [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.2.9.15")] [assembly: AssemblyVersion("1.2.9.16")]
[assembly: AssemblyFileVersion("1.2.9.15")] [assembly: AssemblyFileVersion("1.2.9.16")]

View file

@ -120,6 +120,16 @@ namespace SystemTrayMenu.Properties {
} }
} }
/// <summary>
/// Looks up a localized resource of type System.Drawing.Icon similar to (Icon).
/// </summary>
public static System.Drawing.Icon LinkArrow {
get {
object obj = ResourceManager.GetObject("LinkArrow", resourceCulture);
return ((System.Drawing.Icon)(obj));
}
}
/// <summary> /// <summary>
/// Looks up a localized resource of type System.Drawing.Icon similar to (Icon). /// Looks up a localized resource of type System.Drawing.Icon similar to (Icon).
/// </summary> /// </summary>

View file

@ -112,12 +112,12 @@
<value>2.0</value> <value>2.0</value>
</resheader> </resheader>
<resheader name="reader"> <resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value> <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader> </resheader>
<resheader name="writer"> <resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value> <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader> </resheader>
<assembly alias="System.Windows.Forms" name="System.Windows.Forms, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" /> <assembly alias="System.Windows.Forms" name="System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
<data name="White50Percentage" type="System.Resources.ResXFileRef, System.Windows.Forms"> <data name="White50Percentage" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\White50Percentage.ico;System.Drawing.Icon, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value> <value>..\Resources\White50Percentage.ico;System.Drawing.Icon, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data> </data>
@ -148,4 +148,7 @@
<data name="ic_fluent_settings_28_regular" type="System.Resources.ResXFileRef, System.Windows.Forms"> <data name="ic_fluent_settings_28_regular" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\ic_fluent_settings_28_regular.svg;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value> <value>..\Resources\ic_fluent_settings_28_regular.svg;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</data> </data>
<data name="LinkArrow" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\LinkArrow.ico;System.Drawing.Icon, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
</root> </root>

BIN
Resources/LinkArrow.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

View file

@ -110,10 +110,6 @@
<SpecificVersion>False</SpecificVersion> <SpecificVersion>False</SpecificVersion>
<HintPath>ThirdParty\Clearcove.Logging.dll</HintPath> <HintPath>ThirdParty\Clearcove.Logging.dll</HintPath>
</Reference> </Reference>
<Reference Include="TAFactory.IconPack, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>ThirdParty\TAFactory.IconPack.dll</HintPath>
</Reference>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Compile Update="Properties\Resources.Designer.cs"> <Compile Update="Properties\Resources.Designer.cs">

View file

@ -16,7 +16,6 @@ namespace SystemTrayMenu.Utilities
using System.Text; using System.Text;
using System.Threading; using System.Threading;
using SystemTrayMenu.DllImports; using SystemTrayMenu.DllImports;
using TAFactory.IconPack;
/// <summary> /// <summary>
/// Provides static methods to read system icons for folders and files. /// Provides static methods to read system icons for folders and files.
@ -70,80 +69,9 @@ namespace SystemTrayMenu.Utilities
return cleared; return cleared;
} }
public static Icon GetExtractAllIconsLastWithCache(
string filePath,
bool updateIconInBackground,
bool isMainMenu,
out bool loading)
{
bool linkOverlay = false;
loading = false;
string key = filePath;
string extension = Path.GetExtension(filePath);
if (IsExtensionWithSameIcon(extension))
{
key = extension + linkOverlay;
}
if (!DictIconCache(isMainMenu).TryGetValue(key, out Icon icon) &&
!DictIconCache(!isMainMenu).TryGetValue(key, out icon))
{
icon = Resources.StaticResources.LoadingIcon;
loading = true;
if (updateIconInBackground)
{
new Thread(UpdateIconInBackground).Start();
void UpdateIconInBackground()
{
DictIconCache(isMainMenu).GetOrAdd(key, GetExtractAllIconsLastSTA(filePath));
}
}
}
static Icon GetExtractAllIconsLastSTA(string filePath)
{
Icon icon = null;
if (Thread.CurrentThread.GetApartmentState() == ApartmentState.STA)
{
icon = GetExtractAllIconsLast(filePath);
}
else
{
Thread staThread = new(new ParameterizedThreadStart(StaThreadMethod));
void StaThreadMethod(object obj)
{
icon = GetExtractAllIconsLast(filePath);
}
staThread.SetApartmentState(ApartmentState.STA);
staThread.Start(icon);
staThread.Join();
}
static Icon GetExtractAllIconsLast(string filePath)
{
StringBuilder executable = new(1024);
NativeMethods.Shell32FindExecutable(filePath, string.Empty, executable);
// icon = IconReader.GetFileIcon(executable, false);
// e.g. VS 2019 icon, need another icom in imagelist
List<Icon> extractedIcons = IconHelper.ExtractAllIcons(
executable.ToString());
return extractedIcons.Last();
}
return icon;
}
return icon;
}
public static Icon GetFileIconWithCache( public static Icon GetFileIconWithCache(
string filePath, string pathOrig,
string path,
bool linkOverlay, bool linkOverlay,
bool updateIconInBackground, bool updateIconInBackground,
bool isMainMenu, bool isMainMenu,
@ -151,10 +79,10 @@ namespace SystemTrayMenu.Utilities
string keyPath = "") string keyPath = "")
{ {
loading = false; loading = false;
string extension = Path.GetExtension(filePath); string extension = Path.GetExtension(pathOrig);
IconSize size = IconSize.Large; IconSize size = IconSize.Large;
string key = filePath; string key = pathOrig;
if (!string.IsNullOrEmpty(keyPath)) if (!string.IsNullOrEmpty(keyPath))
{ {
key = keyPath; key = keyPath;
@ -175,7 +103,7 @@ namespace SystemTrayMenu.Utilities
new Thread(UpdateIconInBackground).Start(); new Thread(UpdateIconInBackground).Start();
void UpdateIconInBackground() void UpdateIconInBackground()
{ {
DictIconCache(isMainMenu).GetOrAdd(key, GetIconSTA(filePath, linkOverlay, size, null)); DictIconCache(isMainMenu).GetOrAdd(key, GetIconSTA(pathOrig, path, linkOverlay, size, null));
} }
} }
} }
@ -228,25 +156,25 @@ namespace SystemTrayMenu.Utilities
Icon GetFolder(string keyExtension) Icon GetFolder(string keyExtension)
{ {
return GetIconSTA(path, linkOverlay, size, folderType); return GetIconSTA(path, path, linkOverlay, size, folderType);
} }
return icon; return icon;
} }
public static Icon GetIconSTA(string path, bool linkOverlay, IconSize size, FolderType? folderType) public static Icon GetIconSTA(string pathOrig, string path, bool linkOverlay, IconSize size, FolderType? folderType)
{ {
Icon icon = null; Icon icon = null;
if (Thread.CurrentThread.GetApartmentState() == ApartmentState.STA) if (Thread.CurrentThread.GetApartmentState() == ApartmentState.STA)
{ {
icon = GetIcon(path, linkOverlay, size, folderType); icon = GetIcon(pathOrig, path, linkOverlay, size, folderType);
} }
else else
{ {
Thread staThread = new(new ParameterizedThreadStart(StaThreadMethod)); Thread staThread = new(new ParameterizedThreadStart(StaThreadMethod));
void StaThreadMethod(object obj) void StaThreadMethod(object obj)
{ {
icon = GetIcon(path, linkOverlay, size, folderType); icon = GetIcon(pathOrig, path, linkOverlay, size, folderType);
} }
staThread.SetApartmentState(ApartmentState.STA); staThread.SetApartmentState(ApartmentState.STA);
@ -299,15 +227,34 @@ namespace SystemTrayMenu.Utilities
return isExtensionWithSameIcon; return isExtensionWithSameIcon;
} }
private static Icon GetIcon(string path, bool linkOverlay, IconSize size, FolderType? type) private static Icon GetIcon(string path, string pathOrig, bool linkOverlay, IconSize size, FolderType? type)
{ {
NativeMethods.SHFILEINFO shFileInfo = default; Icon icon;
uint flags = GetFlags(linkOverlay, size, type); if (Path.GetExtension(path).Equals(".ico", StringComparison.InvariantCultureIgnoreCase))
uint attribute = type == null ? NativeMethods.FileAttributeNormal : {
NativeMethods.FileAttributeDirectory; icon = Icon.ExtractAssociatedIcon(path);
IntPtr imageList = NativeMethods.Shell32SHGetFileInfo( }
path, attribute, ref shFileInfo, (uint)Marshal.SizeOf(shFileInfo), flags); else if (Path.GetExtension(pathOrig).Equals(".ico", StringComparison.InvariantCultureIgnoreCase) &&
return GetIcon(path, linkOverlay, shFileInfo, imageList); File.Exists(pathOrig))
{
icon = Icon.ExtractAssociatedIcon(pathOrig);
if (linkOverlay)
{
icon = AddIconOverlay(icon, Properties.Resources.LinkArrow);
}
}
else
{
NativeMethods.SHFILEINFO shFileInfo = default;
uint flags = GetFlags(linkOverlay, size, type);
uint attribute = type == null ? NativeMethods.FileAttributeNormal :
NativeMethods.FileAttributeDirectory;
IntPtr imageList = NativeMethods.Shell32SHGetFileInfo(
path, attribute, ref shFileInfo, (uint)Marshal.SizeOf(shFileInfo), flags);
icon = GetIcon(path, linkOverlay, shFileInfo, imageList);
}
return icon;
} }
private static uint GetFlags(bool linkOverlay, IconSize size, FolderType? folderType) private static uint GetFlags(bool linkOverlay, IconSize size, FolderType? folderType)