mirror of
https://github.com/Hofknecht/SystemTrayMenu.git
synced 2024-05-19 03:42:37 +12:00
This commit is contained in:
parent
a16a3687fa
commit
1e330d40a8
|
@ -545,7 +545,6 @@ namespace SystemTrayMenu.Business
|
||||||
foreach (DataGridViewRow row in dgv.Rows)
|
foreach (DataGridViewRow row in dgv.Rows)
|
||||||
{
|
{
|
||||||
RowData rowData = (RowData)row.Cells[2].Value;
|
RowData rowData = (RowData)row.Cells[2].Value;
|
||||||
rowData?.Dispose();
|
|
||||||
DisposeMenu(rowData.SubMenu);
|
DisposeMenu(rowData.SubMenu);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -759,13 +758,13 @@ namespace SystemTrayMenu.Business
|
||||||
|
|
||||||
if (!AsEnumerable.Any(m => m.Visible))
|
if (!AsEnumerable.Any(m => m.Visible))
|
||||||
{
|
{
|
||||||
openCloseState = OpenCloseState.Default;
|
|
||||||
|
|
||||||
if (IconReader.ClearIfCacheTooBig())
|
if (IconReader.ClearIfCacheTooBig())
|
||||||
{
|
{
|
||||||
GC.Collect();
|
GC.Collect();
|
||||||
MainPreload();
|
MainPreload();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
openCloseState = OpenCloseState.Default;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -463,8 +463,8 @@ namespace SystemTrayMenu
|
||||||
|
|
||||||
private static void UpgradeIfNotUpgraded()
|
private static void UpgradeIfNotUpgraded()
|
||||||
{
|
{
|
||||||
string path = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.PerUserRoaming).FilePath;
|
// string path = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.PerUserRoaming).FilePath;
|
||||||
path = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData);
|
// path = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData);
|
||||||
if (!Settings.Default.IsUpgraded)
|
if (!Settings.Default.IsUpgraded)
|
||||||
{
|
{
|
||||||
Settings.Default.Upgrade();
|
Settings.Default.Upgrade();
|
||||||
|
|
|
@ -17,7 +17,7 @@ namespace SystemTrayMenu.DataClasses
|
||||||
using TAFactory.IconPack;
|
using TAFactory.IconPack;
|
||||||
using Menu = SystemTrayMenu.UserInterface.Menu;
|
using Menu = SystemTrayMenu.UserInterface.Menu;
|
||||||
|
|
||||||
internal class RowData : IDisposable
|
internal class RowData
|
||||||
{
|
{
|
||||||
private static readonly Icon White50PercentageIcon = Properties.Resources.White50Percentage;
|
private static readonly Icon White50PercentageIcon = Properties.Resources.White50Percentage;
|
||||||
private static readonly Icon NotFoundIcon = Properties.Resources.NotFound;
|
private static readonly Icon NotFoundIcon = Properties.Resources.NotFound;
|
||||||
|
@ -26,8 +26,6 @@ namespace SystemTrayMenu.DataClasses
|
||||||
private string arguments;
|
private string arguments;
|
||||||
private string text;
|
private string text;
|
||||||
private Icon icon;
|
private Icon icon;
|
||||||
private bool diposeIcon = true;
|
|
||||||
private bool isDisposed;
|
|
||||||
|
|
||||||
internal RowData()
|
internal RowData()
|
||||||
{
|
{
|
||||||
|
@ -59,13 +57,7 @@ namespace SystemTrayMenu.DataClasses
|
||||||
|
|
||||||
internal bool IconLoading { get; set; }
|
internal bool IconLoading { get; set; }
|
||||||
|
|
||||||
public void Dispose()
|
internal string FilePathIcon { get; set; }
|
||||||
{
|
|
||||||
Dispose(true);
|
|
||||||
#if DEBUG
|
|
||||||
GC.SuppressFinalize(this);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
internal void SetText(string text)
|
internal void SetText(string text)
|
||||||
{
|
{
|
||||||
|
@ -79,9 +71,7 @@ namespace SystemTrayMenu.DataClasses
|
||||||
|
|
||||||
if (HiddenEntry)
|
if (HiddenEntry)
|
||||||
{
|
{
|
||||||
row[0] = IconReader.AddIconOverlay(
|
row[0] = IconReader.AddIconOverlay(data.icon, White50PercentageIcon);
|
||||||
data.icon,
|
|
||||||
White50PercentageIcon);
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -111,10 +101,8 @@ namespace SystemTrayMenu.DataClasses
|
||||||
}
|
}
|
||||||
else if (isDirectory)
|
else if (isDirectory)
|
||||||
{
|
{
|
||||||
icon = IconReader.GetFolderIconSTA(
|
icon = IconReader.GetFolderIconWithCache(TargetFilePathOrig, IconReader.FolderType.Closed, false, true, out bool loading);
|
||||||
TargetFilePath,
|
IconLoading = loading;
|
||||||
IconReader.FolderType.Closed,
|
|
||||||
false);
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -138,18 +126,18 @@ namespace SystemTrayMenu.DataClasses
|
||||||
{
|
{
|
||||||
handled = SetSln();
|
handled = SetSln();
|
||||||
}
|
}
|
||||||
|
else if (fileExtension == ".appref-ms")
|
||||||
|
{
|
||||||
|
showOverlay = true;
|
||||||
|
}
|
||||||
|
|
||||||
if (!handled)
|
if (!handled)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
icon = IconReader.GetFileIconWithCache(
|
FilePathIcon = TargetFilePathOrig;
|
||||||
TargetFilePathOrig,
|
icon = IconReader.GetFileIconWithCache(FilePathIcon, showOverlay, true, out bool loading);
|
||||||
showOverlay,
|
|
||||||
true,
|
|
||||||
out bool loading);
|
|
||||||
IconLoading = loading;
|
IconLoading = loading;
|
||||||
diposeIcon = false;
|
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
|
@ -215,8 +203,7 @@ namespace SystemTrayMenu.DataClasses
|
||||||
OpenItem(e, ref toCloseByDoubleClick);
|
OpenItem(e, ref toCloseByDoubleClick);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ContainsMenu &&
|
if (ContainsMenu && (e == null || e.Button == MouseButtons.Left))
|
||||||
(e == null || e.Button == MouseButtons.Left))
|
|
||||||
{
|
{
|
||||||
Log.ProcessStart(TargetFilePath);
|
Log.ProcessStart(TargetFilePath);
|
||||||
if (!Properties.Settings.Default.StaysOpenWhenItemClicked)
|
if (!Properties.Settings.Default.StaysOpenWhenItemClicked)
|
||||||
|
@ -228,21 +215,31 @@ namespace SystemTrayMenu.DataClasses
|
||||||
|
|
||||||
internal Icon ReadLoadedIcon()
|
internal Icon ReadLoadedIcon()
|
||||||
{
|
{
|
||||||
bool showOverlay = false;
|
if (ContainsMenu)
|
||||||
string fileExtension = Path.GetExtension(TargetFilePath);
|
|
||||||
if (fileExtension == ".lnk" || fileExtension == ".url")
|
|
||||||
{
|
{
|
||||||
showOverlay = true;
|
icon = IconReader.GetFolderIconWithCache(TargetFilePathOrig, IconReader.FolderType.Closed, false, false, out bool loading);
|
||||||
|
IconLoading = loading;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
bool showOverlay = false;
|
||||||
|
string fileExtension = Path.GetExtension(TargetFilePath);
|
||||||
|
if (fileExtension == ".lnk" || fileExtension == ".url" || fileExtension == ".appref-ms")
|
||||||
|
{
|
||||||
|
showOverlay = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
string filePath = FilePathIcon;
|
||||||
|
if (string.IsNullOrEmpty(filePath))
|
||||||
|
{
|
||||||
|
filePath = TargetFilePathOrig;
|
||||||
|
}
|
||||||
|
|
||||||
|
icon = IconReader.GetFileIconWithCache(filePath, showOverlay, false, out bool loading);
|
||||||
|
IconLoading = loading;
|
||||||
}
|
}
|
||||||
|
|
||||||
icon = IconReader.GetFileIconWithCache(
|
if (!IconLoading && icon == null)
|
||||||
TargetFilePathOrig,
|
|
||||||
showOverlay,
|
|
||||||
false,
|
|
||||||
out bool loading);
|
|
||||||
IconLoading = loading;
|
|
||||||
|
|
||||||
if (!loading && icon == null)
|
|
||||||
{
|
{
|
||||||
icon = NotFoundIcon;
|
icon = NotFoundIcon;
|
||||||
}
|
}
|
||||||
|
@ -250,19 +247,6 @@ namespace SystemTrayMenu.DataClasses
|
||||||
return icon;
|
return icon;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected virtual void Dispose(bool disposing)
|
|
||||||
{
|
|
||||||
if (!isDisposed)
|
|
||||||
{
|
|
||||||
if (diposeIcon)
|
|
||||||
{
|
|
||||||
icon?.Dispose();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
isDisposed = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OpenItem(MouseEventArgs e, ref bool toCloseByOpenItem)
|
private void OpenItem(MouseEventArgs e, ref bool toCloseByOpenItem)
|
||||||
{
|
{
|
||||||
if (!ContainsMenu &&
|
if (!ContainsMenu &&
|
||||||
|
@ -285,7 +269,8 @@ namespace SystemTrayMenu.DataClasses
|
||||||
|
|
||||||
if (string.IsNullOrEmpty(Path.GetExtension(resolvedLnkPath)))
|
if (string.IsNullOrEmpty(Path.GetExtension(resolvedLnkPath)))
|
||||||
{
|
{
|
||||||
icon = IconReader.GetFolderIconSTA(TargetFilePath, IconReader.FolderType.Open, true);
|
icon = IconReader.GetFolderIconWithCache(TargetFilePathOrig, IconReader.FolderType.Open, true, true, out bool loading);
|
||||||
|
IconLoading = loading;
|
||||||
handled = true;
|
handled = true;
|
||||||
isLnkDirectory = true;
|
isLnkDirectory = true;
|
||||||
}
|
}
|
||||||
|
@ -300,8 +285,7 @@ namespace SystemTrayMenu.DataClasses
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
IWshShell shell = new WshShell();
|
IWshShell shell = new WshShell();
|
||||||
IWshShortcut lnk = shell.CreateShortcut(TargetFilePath)
|
IWshShortcut lnk = shell.CreateShortcut(TargetFilePath) as IWshShortcut;
|
||||||
as IWshShortcut;
|
|
||||||
arguments = lnk.Arguments;
|
arguments = lnk.Arguments;
|
||||||
workingDirectory = lnk.WorkingDirectory;
|
workingDirectory = lnk.WorkingDirectory;
|
||||||
TargetFilePath = resolvedLnkPath;
|
TargetFilePath = resolvedLnkPath;
|
||||||
|
@ -324,15 +308,17 @@ namespace SystemTrayMenu.DataClasses
|
||||||
{
|
{
|
||||||
if (FileUrl.GetDefaultBrowserPath(out string browserPath))
|
if (FileUrl.GetDefaultBrowserPath(out string browserPath))
|
||||||
{
|
{
|
||||||
icon = IconReader.GetFileIconWithCache(browserPath, true, true, out bool loading);
|
FilePathIcon = browserPath;
|
||||||
|
icon = IconReader.GetFileIconWithCache(FilePathIcon, true, true, out bool loading);
|
||||||
IconLoading = loading;
|
IconLoading = loading;
|
||||||
diposeIcon = false;
|
|
||||||
handled = true;
|
handled = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (System.IO.File.Exists(iconFile))
|
else if (System.IO.File.Exists(iconFile))
|
||||||
{
|
{
|
||||||
icon = Icon.ExtractAssociatedIcon(iconFile);
|
FilePathIcon = iconFile;
|
||||||
|
icon = IconReader.GetFileIconWithCache(FilePathIcon, true, true, out bool loading);
|
||||||
|
IconLoading = loading;
|
||||||
handled = true;
|
handled = true;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -342,10 +328,7 @@ namespace SystemTrayMenu.DataClasses
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
Log.Warn(
|
Log.Warn($"path:'{TargetFilePath}', iconFile:'{iconFile}'", ex);
|
||||||
$"path:'{TargetFilePath}', " +
|
|
||||||
$"iconFile:'{iconFile}'",
|
|
||||||
ex);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
SetText($"{FileInfo.Name[0..^4]}");
|
SetText($"{FileInfo.Name[0..^4]}");
|
||||||
|
@ -356,24 +339,15 @@ namespace SystemTrayMenu.DataClasses
|
||||||
private bool SetSln()
|
private bool SetSln()
|
||||||
{
|
{
|
||||||
bool handled = false;
|
bool handled = false;
|
||||||
StringBuilder executable = new StringBuilder(1024);
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
DllImports.NativeMethods.Shell32FindExecutable(TargetFilePath, string.Empty, executable);
|
icon = IconReader.GetExtractAllIconsLastWithCache(TargetFilePathOrig, true, out bool loading);
|
||||||
|
IconLoading = loading;
|
||||||
// icon = IconReader.GetFileIcon(executable, false);
|
|
||||||
// e.g. VS 2019 icon, need another icom in imagelist
|
|
||||||
List<Icon> extractedIcons = IconHelper.ExtractAllIcons(
|
|
||||||
executable.ToString());
|
|
||||||
icon = extractedIcons.Last();
|
|
||||||
handled = true;
|
handled = true;
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
Log.Warn(
|
Log.Warn($"path:'{TargetFilePath}'", ex);
|
||||||
$"path:'{TargetFilePath}', " +
|
|
||||||
$"executable:'{executable}'",
|
|
||||||
ex);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return handled;
|
return handled;
|
||||||
|
|
|
@ -31,9 +31,7 @@ namespace SystemTrayMenu.Helper
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
{
|
{
|
||||||
Dispose(true);
|
Dispose(true);
|
||||||
#if DEBUG
|
|
||||||
GC.SuppressFinalize(this);
|
GC.SuppressFinalize(this);
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
internal void CellMouseEnter(object sender, DataGridViewCellEventArgs newEventArgs)
|
internal void CellMouseEnter(object sender, DataGridViewCellEventArgs newEventArgs)
|
||||||
|
|
|
@ -85,7 +85,7 @@ namespace SystemTrayMenu.Helpers
|
||||||
}
|
}
|
||||||
|
|
||||||
title = Truncate(title, 128); // max 255
|
title = Truncate(title, 128); // max 255
|
||||||
string Truncate(string value, int maxLength)
|
static string Truncate(string value, int maxLength)
|
||||||
{
|
{
|
||||||
if (!string.IsNullOrEmpty(value) &&
|
if (!string.IsNullOrEmpty(value) &&
|
||||||
value.Length > maxLength)
|
value.Length > maxLength)
|
||||||
|
|
|
@ -54,9 +54,7 @@ namespace SystemTrayMenu.UserInterface
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
{
|
{
|
||||||
Dispose(true);
|
Dispose(true);
|
||||||
#if DEBUG
|
|
||||||
GC.SuppressFinalize(this);
|
GC.SuppressFinalize(this);
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
internal void Fade(FadingState state)
|
internal void Fade(FadingState state)
|
||||||
|
|
|
@ -18,7 +18,6 @@ namespace SystemTrayMenu.DllImports
|
||||||
[Flags]
|
[Flags]
|
||||||
internal enum TPM : uint
|
internal enum TPM : uint
|
||||||
{
|
{
|
||||||
#pragma warning disable SA1602 // Enumeration items should be documented
|
|
||||||
LEFTBUTTON = 0x0000, // LEFTALIGN = 0x0000, // TOPALIGN = 0x0000, // HORIZONTAL = 0x0000,
|
LEFTBUTTON = 0x0000, // LEFTALIGN = 0x0000, // TOPALIGN = 0x0000, // HORIZONTAL = 0x0000,
|
||||||
RIGHTBUTTON = 0x0002,
|
RIGHTBUTTON = 0x0002,
|
||||||
CENTERALIGN = 0x0004,
|
CENTERALIGN = 0x0004,
|
||||||
|
@ -35,7 +34,6 @@ namespace SystemTrayMenu.DllImports
|
||||||
VERNEGANIMATION = 0x2000,
|
VERNEGANIMATION = 0x2000,
|
||||||
NOANIMATION = 0x4000,
|
NOANIMATION = 0x4000,
|
||||||
LAYOUTRTL = 0x8000,
|
LAYOUTRTL = 0x8000,
|
||||||
#pragma warning restore SA1602 // Enumeration items should be documented
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
|
@ -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.0.21.1")]
|
[assembly: AssemblyVersion("1.0.21.2")]
|
||||||
[assembly: AssemblyFileVersion("1.0.21.1")]
|
[assembly: AssemblyFileVersion("1.0.21.2")]
|
||||||
|
|
2
UserInterface/Menu.Designer.cs
generated
2
UserInterface/Menu.Designer.cs
generated
|
@ -295,7 +295,7 @@
|
||||||
//
|
//
|
||||||
// timerUpdateIcons
|
// timerUpdateIcons
|
||||||
//
|
//
|
||||||
this.timerUpdateIcons.Interval = 300;
|
this.timerUpdateIcons.Interval = 100;
|
||||||
this.timerUpdateIcons.Tick += new System.EventHandler(this.TimerUpdateIcons_Tick);
|
this.timerUpdateIcons.Tick += new System.EventHandler(this.TimerUpdateIcons_Tick);
|
||||||
//
|
//
|
||||||
// Menu
|
// Menu
|
||||||
|
|
|
@ -1063,9 +1063,7 @@ namespace SystemTrayMenu.Utilities
|
||||||
int nResult = DllImports.NativeMethods.Shell32SHGetDesktopFolder(out IntPtr pUnkownDesktopFolder);
|
int nResult = DllImports.NativeMethods.Shell32SHGetDesktopFolder(out IntPtr pUnkownDesktopFolder);
|
||||||
if (nResult != ResultOK)
|
if (nResult != ResultOK)
|
||||||
{
|
{
|
||||||
#pragma warning disable CA1303 // Do not pass literals as localized parameters
|
|
||||||
throw new ShellContextMenuException("Failed to get the desktop shell folder");
|
throw new ShellContextMenuException("Failed to get the desktop shell folder");
|
||||||
#pragma warning restore CA1303 //=> Exceptions not translated in logfile => OK
|
|
||||||
}
|
}
|
||||||
|
|
||||||
oDesktopFolder = (IShellFolder)Marshal.GetTypedObjectForIUnknown(pUnkownDesktopFolder, typeof(IShellFolder));
|
oDesktopFolder = (IShellFolder)Marshal.GetTypedObjectForIUnknown(pUnkownDesktopFolder, typeof(IShellFolder));
|
||||||
|
|
|
@ -10,9 +10,11 @@ namespace SystemTrayMenu.Utilities
|
||||||
using System.Drawing;
|
using System.Drawing;
|
||||||
using System.Drawing.Imaging;
|
using System.Drawing.Imaging;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
|
using System.Text;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using TAFactory.IconPack;
|
||||||
|
|
||||||
// from https://www.codeproject.com/Articles/2532/Obtaining-and-managing-file-and-folder-icons-using
|
// from https://www.codeproject.com/Articles/2532/Obtaining-and-managing-file-and-folder-icons-using
|
||||||
// added ImageList_GetIcon, IconCache, AddIconOverlay
|
// added ImageList_GetIcon, IconCache, AddIconOverlay
|
||||||
|
@ -62,7 +64,81 @@ namespace SystemTrayMenu.Utilities
|
||||||
return cleared;
|
return cleared;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Icon GetFileIconWithCache(string filePath, bool linkOverlay, bool updateIconInBackground, out bool loading)
|
public static Icon GetExtractAllIconsLastWithCache(string filePath, bool updateIconInBackground, out bool loading)
|
||||||
|
{
|
||||||
|
bool linkOverlay = false;
|
||||||
|
loading = false;
|
||||||
|
string key = filePath;
|
||||||
|
|
||||||
|
string extension = Path.GetExtension(filePath);
|
||||||
|
|
||||||
|
if (IsExtensionWithSameIcon(extension))
|
||||||
|
{
|
||||||
|
key = extension + linkOverlay;
|
||||||
|
}
|
||||||
|
|
||||||
|
ClearBadIcons();
|
||||||
|
|
||||||
|
if (!DictIconCache.TryGetValue(key, out Icon icon))
|
||||||
|
{
|
||||||
|
icon = LoadingIcon;
|
||||||
|
loading = true;
|
||||||
|
|
||||||
|
if (updateIconInBackground)
|
||||||
|
{
|
||||||
|
new Thread(UpdateIconInBackground).Start();
|
||||||
|
void UpdateIconInBackground()
|
||||||
|
{
|
||||||
|
DictIconCache.GetOrAdd(key, GetExtractAllIconsLast);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Icon GetExtractAllIconsLast(string keyExtension)
|
||||||
|
{
|
||||||
|
return GetExtractAllIconsLastSTA(filePath);
|
||||||
|
}
|
||||||
|
|
||||||
|
return icon;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Icon GetExtractAllIconsLastSTA(string filePath)
|
||||||
|
{
|
||||||
|
Icon icon = null;
|
||||||
|
|
||||||
|
if (Thread.CurrentThread.GetApartmentState() == ApartmentState.STA)
|
||||||
|
{
|
||||||
|
icon = GetExtractAllIconsLast(filePath);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Thread staThread = new Thread(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 StringBuilder(1024);
|
||||||
|
DllImports.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;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Icon GetFileIconWithCache(string filePath, bool linkOverlay, bool updateIconInBackground, out bool loading, string keyPath = "")
|
||||||
{
|
{
|
||||||
loading = false;
|
loading = false;
|
||||||
string extension = Path.GetExtension(filePath);
|
string extension = Path.GetExtension(filePath);
|
||||||
|
@ -73,11 +149,18 @@ namespace SystemTrayMenu.Utilities
|
||||||
}
|
}
|
||||||
|
|
||||||
string key = filePath;
|
string key = filePath;
|
||||||
|
if (!string.IsNullOrEmpty(keyPath))
|
||||||
|
{
|
||||||
|
key = keyPath;
|
||||||
|
}
|
||||||
|
|
||||||
if (IsExtensionWithSameIcon(extension))
|
if (IsExtensionWithSameIcon(extension))
|
||||||
{
|
{
|
||||||
key = extension + linkOverlay;
|
key = extension + linkOverlay;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ClearBadIcons();
|
||||||
|
|
||||||
if (!DictIconCache.TryGetValue(key, out Icon icon))
|
if (!DictIconCache.TryGetValue(key, out Icon icon))
|
||||||
{
|
{
|
||||||
icon = LoadingIcon;
|
icon = LoadingIcon;
|
||||||
|
@ -101,6 +184,48 @@ namespace SystemTrayMenu.Utilities
|
||||||
return icon;
|
return icon;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static Icon GetFolderIconWithCache(string path, FolderType folderType, bool linkOverlay, bool updateIconInBackground, out bool loading)
|
||||||
|
{
|
||||||
|
loading = false;
|
||||||
|
IconSize size = IconSize.Small;
|
||||||
|
|
||||||
|
// with this we get another folder icon than windows explorer
|
||||||
|
// if (Scaling.Factor > 1)
|
||||||
|
// {
|
||||||
|
// size = IconSize.Large;
|
||||||
|
// }
|
||||||
|
string key = path;
|
||||||
|
|
||||||
|
// Maybe we can reduce object when checking if a standard folder
|
||||||
|
// if (IsStandardFolderIcon(key))
|
||||||
|
// {
|
||||||
|
// key = "folder" + linkOverlay;
|
||||||
|
// }
|
||||||
|
ClearBadIcons();
|
||||||
|
|
||||||
|
if (!DictIconCache.TryGetValue(key, out Icon icon))
|
||||||
|
{
|
||||||
|
icon = LoadingIcon;
|
||||||
|
loading = true;
|
||||||
|
|
||||||
|
if (updateIconInBackground)
|
||||||
|
{
|
||||||
|
new Thread(UpdateIconInBackground).Start();
|
||||||
|
void UpdateIconInBackground()
|
||||||
|
{
|
||||||
|
DictIconCache.GetOrAdd(key, GetFolder);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Icon GetFolder(string keyExtension)
|
||||||
|
{
|
||||||
|
return GetFolderIconSTA(path, folderType, linkOverlay, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
return icon;
|
||||||
|
}
|
||||||
|
|
||||||
public static Icon GetFolderIconSTA(
|
public static Icon GetFolderIconSTA(
|
||||||
string directoryPath,
|
string directoryPath,
|
||||||
FolderType folderType,
|
FolderType folderType,
|
||||||
|
@ -108,13 +233,30 @@ namespace SystemTrayMenu.Utilities
|
||||||
IconSize size = IconSize.Small)
|
IconSize size = IconSize.Small)
|
||||||
{
|
{
|
||||||
Icon icon = null;
|
Icon icon = null;
|
||||||
|
if (Thread.CurrentThread.GetApartmentState() == ApartmentState.STA)
|
||||||
|
{
|
||||||
|
icon = GetFolderIcon(
|
||||||
|
directoryPath,
|
||||||
|
folderType,
|
||||||
|
linkOverlay,
|
||||||
|
size);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Thread staThread = new Thread(new ParameterizedThreadStart(StaThreadMethod));
|
||||||
|
void StaThreadMethod(object obj)
|
||||||
|
{
|
||||||
|
icon = GetFolderIcon(
|
||||||
|
directoryPath,
|
||||||
|
folderType,
|
||||||
|
linkOverlay,
|
||||||
|
size);
|
||||||
|
}
|
||||||
|
|
||||||
Task<Icon> task = Task.Factory.StartNew(() => GetFolderIcon(
|
staThread.SetApartmentState(ApartmentState.STA);
|
||||||
directoryPath,
|
staThread.Start(icon);
|
||||||
folderType,
|
staThread.Join();
|
||||||
linkOverlay,
|
}
|
||||||
size));
|
|
||||||
icon = task.Result;
|
|
||||||
|
|
||||||
return icon;
|
return icon;
|
||||||
}
|
}
|
||||||
|
@ -182,20 +324,28 @@ namespace SystemTrayMenu.Utilities
|
||||||
Icon icon = null;
|
Icon icon = null;
|
||||||
if (originalIcon != null)
|
if (originalIcon != null)
|
||||||
{
|
{
|
||||||
using Bitmap target = new Bitmap(
|
using Bitmap target = new Bitmap(originalIcon.Width, originalIcon.Height, PixelFormat.Format32bppArgb);
|
||||||
originalIcon.Width,
|
using Graphics graphics = Graphics.FromImage(target);
|
||||||
originalIcon.Height,
|
|
||||||
PixelFormat.Format32bppArgb);
|
|
||||||
Graphics graphics = Graphics.FromImage(target);
|
|
||||||
graphics.DrawIcon(originalIcon, 0, 0);
|
graphics.DrawIcon(originalIcon, 0, 0);
|
||||||
graphics.DrawIcon(overlay, 0, 0);
|
graphics.DrawIcon(overlay, 0, 0);
|
||||||
target.MakeTransparent(target.GetPixel(1, 1));
|
target.MakeTransparent(target.GetPixel(1, 1));
|
||||||
icon = Icon.FromHandle(target.GetHicon());
|
IntPtr hIcon = target.GetHicon();
|
||||||
|
icon = (Icon)Icon.FromHandle(hIcon).Clone();
|
||||||
|
DllImports.NativeMethods.User32DestroyIcon(hIcon);
|
||||||
}
|
}
|
||||||
|
|
||||||
return icon;
|
return icon;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static void ClearBadIcons()
|
||||||
|
{
|
||||||
|
IEnumerable<string> badKeysList = DictIconCache.Where(x => x.Value == null).Select(x => x.Key);
|
||||||
|
foreach (string badKey in badKeysList)
|
||||||
|
{
|
||||||
|
DictIconCache.Remove(badKey, out _);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private static bool IsExtensionWithSameIcon(string fileExtension)
|
private static bool IsExtensionWithSameIcon(string fileExtension)
|
||||||
{
|
{
|
||||||
bool isExtensionWithSameIcon = true;
|
bool isExtensionWithSameIcon = true;
|
||||||
|
@ -213,8 +363,22 @@ namespace SystemTrayMenu.Utilities
|
||||||
{
|
{
|
||||||
Icon icon = null;
|
Icon icon = null;
|
||||||
|
|
||||||
Task<Icon> task = Task.Factory.StartNew(() => GetFileIcon(filePath, linkOverlay, size));
|
if (Thread.CurrentThread.GetApartmentState() == ApartmentState.STA)
|
||||||
icon = task.Result;
|
{
|
||||||
|
icon = GetFileIcon(filePath, linkOverlay, size);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Thread staThread = new Thread(new ParameterizedThreadStart(StaThreadMethod));
|
||||||
|
void StaThreadMethod(object obj)
|
||||||
|
{
|
||||||
|
icon = GetFileIcon(filePath, linkOverlay, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
staThread.SetApartmentState(ApartmentState.STA);
|
||||||
|
staThread.Start(icon);
|
||||||
|
staThread.Join();
|
||||||
|
}
|
||||||
|
|
||||||
return icon;
|
return icon;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue