v1.2
This commit is contained in:
@@ -0,0 +1,50 @@
|
||||
// <copyright file="DataGridViewExtensions.cs" company="PlaceholderCompany">
|
||||
// Copyright (c) PlaceholderCompany. All rights reserved.
|
||||
// </copyright>
|
||||
|
||||
namespace FSI.BT.Tools.SystemTrayMenu.Utilities
|
||||
{
|
||||
using System;
|
||||
using System.Data;
|
||||
using System.Drawing;
|
||||
using System.Windows.Forms;
|
||||
using FSI.BT.Tools.Global.Utilities;
|
||||
using FSI.BT.Tools.SystemTrayMenu.DataClasses;
|
||||
|
||||
internal static class DataGridViewExtensions
|
||||
{
|
||||
private const float WidthMin = 100f;
|
||||
|
||||
/// <summary>
|
||||
/// dgv.AutoResizeColumns() was too slow ~45ms.
|
||||
/// </summary>
|
||||
/// <param name="dgv">datagridview.</param>
|
||||
internal static void FastAutoSizeColumns(this DataGridView dgv)
|
||||
{
|
||||
using Graphics graphics = dgv.CreateGraphics();
|
||||
graphics.TextRenderingHint = System.Drawing.Text.TextRenderingHint.AntiAlias;
|
||||
float widthMax = WidthMin;
|
||||
DataTable data = (DataTable)dgv.DataSource;
|
||||
foreach (DataRow row in data.Rows)
|
||||
{
|
||||
float checkWidth = graphics.MeasureString(
|
||||
((RowData)row[2]).Text + "___",
|
||||
dgv.RowTemplate.DefaultCellStyle.Font).Width;
|
||||
if (checkWidth > widthMax)
|
||||
{
|
||||
widthMax = checkWidth;
|
||||
}
|
||||
}
|
||||
|
||||
int widthMaxInPixel = (int)(Scaling.Factor * Scaling.FactorByDpi *
|
||||
400f * (Global.Vars.SystemTrayMenuSettings.WidthMaxInPercent / 100f));
|
||||
widthMax = Math.Min(widthMax, widthMaxInPixel);
|
||||
dgv.Columns[1].Width = (int)(widthMax + 0.5);
|
||||
double factorIconSizeInPercent = Global.Vars.SystemTrayMenuSettings.IconSizeInPercent / 100f;
|
||||
|
||||
// IcoWidth 100% = 21px, 175% is 33, +3+2 is padding from ColumnIcon
|
||||
float icoWidth = (16 * Scaling.FactorByDpi) + 5;
|
||||
dgv.Columns[0].Width = (int)((icoWidth * factorIconSizeInPercent * Scaling.Factor) + 0.5);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
// <copyright file="DirectoryBySearchPattern.cs" company="PlaceholderCompany">
|
||||
// Copyright (c) PlaceholderCompany. All rights reserved.
|
||||
// </copyright>
|
||||
// see also: https://www.codeproject.com/Articles/2532/Obtaining-and-managing-file-and-folder-icons-using.
|
||||
|
||||
namespace FSI.BT.Tools.SystemTrayMenu.Utilities
|
||||
{
|
||||
using System.Collections.Generic;
|
||||
|
||||
public static class DirectoryBySearchPattern
|
||||
{
|
||||
public static List<string> GetFiles(string path, string searchPatternCombined)
|
||||
{
|
||||
string[] searchPatterns = searchPatternCombined.Split('|');
|
||||
List<string> files = new();
|
||||
foreach (string searchPattern in searchPatterns)
|
||||
{
|
||||
files.AddRange(System.IO.Directory.GetFiles(path, searchPattern));
|
||||
}
|
||||
|
||||
return files;
|
||||
}
|
||||
}
|
||||
}
|
||||
99
FSI.BT.Tools/SystemTrayMenu/Utilities/File/FileLnk.cs
Normal file
99
FSI.BT.Tools/SystemTrayMenu/Utilities/File/FileLnk.cs
Normal file
@@ -0,0 +1,99 @@
|
||||
// <copyright file="FileLnk.cs" company="PlaceholderCompany">
|
||||
// Copyright (c) PlaceholderCompany. All rights reserved.
|
||||
// </copyright>
|
||||
|
||||
namespace FSI.BT.Tools.SystemTrayMenu.Utilities
|
||||
{
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Threading;
|
||||
using FSI.BT.Tools.Global.Utilities;
|
||||
using Shell32;
|
||||
|
||||
internal class FileLnk
|
||||
{
|
||||
public static string GetResolvedFileName(string shortcutFilename, out bool isFolder)
|
||||
{
|
||||
bool isFolderByShell = false;
|
||||
string resolvedFilename = string.Empty;
|
||||
if (Thread.CurrentThread.GetApartmentState() == ApartmentState.STA)
|
||||
{
|
||||
resolvedFilename = GetShortcutFileNamePath(shortcutFilename, out isFolderByShell);
|
||||
}
|
||||
else
|
||||
{
|
||||
Thread staThread = new(new ParameterizedThreadStart(StaThreadMethod));
|
||||
void StaThreadMethod(object obj)
|
||||
{
|
||||
resolvedFilename = GetShortcutFileNamePath(shortcutFilename, out isFolderByShell);
|
||||
}
|
||||
|
||||
staThread.SetApartmentState(ApartmentState.STA);
|
||||
staThread.Start(shortcutFilename);
|
||||
staThread.Join();
|
||||
}
|
||||
|
||||
isFolder = isFolderByShell;
|
||||
return resolvedFilename;
|
||||
}
|
||||
|
||||
public static bool IsNetworkRoot(string path)
|
||||
{
|
||||
return path.StartsWith(@"\\", StringComparison.InvariantCulture) &&
|
||||
!path[2..].Contains('\\', StringComparison.InvariantCulture);
|
||||
}
|
||||
|
||||
private static string GetShortcutFileNamePath(object shortcutFilename, out bool isFolder)
|
||||
{
|
||||
string resolvedFilename = string.Empty;
|
||||
isFolder = false;
|
||||
try
|
||||
{
|
||||
string pathOnly = Path.GetDirectoryName((string)shortcutFilename);
|
||||
string filenameOnly = Path.GetFileName((string)shortcutFilename);
|
||||
|
||||
Shell shell = new();
|
||||
Folder folder = shell.NameSpace(pathOnly);
|
||||
if (folder == null)
|
||||
{
|
||||
Log.Info($"{nameof(GetShortcutFileNamePath)} folder == null for path:'{shortcutFilename}'");
|
||||
return resolvedFilename;
|
||||
}
|
||||
|
||||
FolderItem folderItem = folder.ParseName(filenameOnly);
|
||||
if (folderItem == null)
|
||||
{
|
||||
Log.Info($"{nameof(GetShortcutFileNamePath)} folderItem == null for path:'{shortcutFilename}'");
|
||||
return resolvedFilename;
|
||||
}
|
||||
|
||||
ShellLinkObject link = (ShellLinkObject)folderItem.GetLink;
|
||||
isFolder = link.Target.IsFolder;
|
||||
if (string.IsNullOrEmpty(link.Path))
|
||||
{
|
||||
// https://github.com/Hofknecht/SystemTrayMenu/issues/242
|
||||
// do not set CLSID key (GUID) shortcuts as resolvedFilename
|
||||
if (!link.Target.Path.Contains("::{"))
|
||||
{
|
||||
resolvedFilename = link.Target.Path;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
resolvedFilename = link.Path;
|
||||
}
|
||||
}
|
||||
catch (UnauthorizedAccessException)
|
||||
{
|
||||
// https://stackoverflow.com/questions/2934420/why-do-i-get-e-accessdenied-when-reading-public-shortcuts-through-shell32
|
||||
// e.g. Administrative Tools\Component Services.lnk which can not be resolved, do not spam the logfile in this case
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.Warn($"shortcutFilename:'{shortcutFilename}'", ex);
|
||||
}
|
||||
|
||||
return resolvedFilename;
|
||||
}
|
||||
}
|
||||
}
|
||||
329
FSI.BT.Tools/SystemTrayMenu/Utilities/File/IconReader.cs
Normal file
329
FSI.BT.Tools/SystemTrayMenu/Utilities/File/IconReader.cs
Normal file
@@ -0,0 +1,329 @@
|
||||
// <copyright file="IconReader.cs" company="PlaceholderCompany">
|
||||
// Copyright (c) PlaceholderCompany. All rights reserved.
|
||||
// </copyright>
|
||||
// see also: https://www.codeproject.com/Articles/2532/Obtaining-and-managing-file-and-folder-icons-using.
|
||||
|
||||
namespace FSI.BT.Tools.SystemTrayMenu.Utilities
|
||||
{
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.Drawing.Imaging;
|
||||
using System.IO;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Threading;
|
||||
using FSI.BT.Tools.Global.DllImports;
|
||||
using FSI.BT.Tools.Global.Utilities;
|
||||
|
||||
/// <summary>
|
||||
/// Provides static methods to read system icons for folders and files.
|
||||
/// </summary>
|
||||
public static class IconReader
|
||||
{
|
||||
private static readonly ConcurrentDictionary<string, Icon> DictIconCacheMainMenu = new();
|
||||
private static readonly ConcurrentDictionary<string, Icon> DictIconCacheSubMenus = new();
|
||||
|
||||
public enum IconSize
|
||||
{
|
||||
Large = 0, // 32x32 pixels
|
||||
Small = 1, // 16x16 pixels
|
||||
}
|
||||
|
||||
public enum FolderType
|
||||
{
|
||||
Open = 0,
|
||||
Closed = 1,
|
||||
}
|
||||
|
||||
// see https://github.com/Hofknecht/SystemTrayMenu/issues/209.
|
||||
public static bool MainPreload { get; set; }
|
||||
|
||||
public static void Dispose(bool includingMainMenu = true)
|
||||
{
|
||||
if (includingMainMenu)
|
||||
{
|
||||
foreach (Icon icon in DictIconCacheMainMenu.Values)
|
||||
{
|
||||
icon?.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
foreach (Icon icon in DictIconCacheSubMenus.Values)
|
||||
{
|
||||
icon?.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
public static bool ClearIfCacheTooBig()
|
||||
{
|
||||
bool cleared = false;
|
||||
if (DictIconCacheSubMenus.Count > Global.Vars.SystemTrayMenuSettings.ClearCacheIfMoreThanThisNumberOfItems)
|
||||
{
|
||||
Dispose(false);
|
||||
DictIconCacheSubMenus.Clear();
|
||||
cleared = true;
|
||||
}
|
||||
|
||||
return cleared;
|
||||
}
|
||||
|
||||
public static void RemoveIconFromCache(string path)
|
||||
{
|
||||
if (DictIconCacheMainMenu.Remove(path, out Icon iconToRemove))
|
||||
{
|
||||
iconToRemove?.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
public static Icon GetFileIconWithCache(
|
||||
string path,
|
||||
string resolvedPath,
|
||||
bool linkOverlay,
|
||||
bool updateIconInBackground,
|
||||
bool isMainMenu,
|
||||
out bool loading,
|
||||
string keyPath = "")
|
||||
{
|
||||
loading = false;
|
||||
string extension = Path.GetExtension(path);
|
||||
IconSize size = IconSize.Small;
|
||||
if (Scaling.Factor >= 1.25f ||
|
||||
Scaling.FactorByDpi >= 1.25f ||
|
||||
Global.Vars.SystemTrayMenuSettings.IconSizeInPercent / 100f >= 1.25f)
|
||||
{
|
||||
size = IconSize.Large;
|
||||
}
|
||||
|
||||
string key = path;
|
||||
if (!string.IsNullOrEmpty(keyPath))
|
||||
{
|
||||
key = keyPath;
|
||||
}
|
||||
|
||||
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, GetIconSTA(path, resolvedPath, linkOverlay, size, false));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return icon;
|
||||
}
|
||||
|
||||
public static Icon GetFolderIconWithCache(
|
||||
string path,
|
||||
bool linkOverlay,
|
||||
bool updateIconInBackground,
|
||||
bool isMainMenu,
|
||||
out bool loading)
|
||||
{
|
||||
loading = false;
|
||||
|
||||
IconSize size = IconSize.Small;
|
||||
if (Scaling.Factor >= 1.25f ||
|
||||
Scaling.FactorByDpi >= 1.25f ||
|
||||
Global.Vars.SystemTrayMenuSettings.IconSizeInPercent / 100f >= 1.25f)
|
||||
{
|
||||
// IconSize.Large returns another folder icon than windows explorer
|
||||
size = IconSize.Large;
|
||||
}
|
||||
|
||||
string key = path;
|
||||
|
||||
if (!DictIconCache(isMainMenu).TryGetValue(key, out Icon icon) &&
|
||||
!DictIconCache(!isMainMenu).TryGetValue(key, out icon))
|
||||
{
|
||||
icon = Resources.StaticResources.LoadingIcon;
|
||||
loading = true;
|
||||
|
||||
if (updateIconInBackground)
|
||||
{
|
||||
if (MainPreload)
|
||||
{
|
||||
DictIconCache(isMainMenu).GetOrAdd(key, GetFolder);
|
||||
}
|
||||
else
|
||||
{
|
||||
new Thread(UpdateIconInBackground).Start();
|
||||
void UpdateIconInBackground()
|
||||
{
|
||||
DictIconCache(isMainMenu).GetOrAdd(key, GetFolder);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Icon GetFolder(string keyExtension)
|
||||
{
|
||||
return GetIconSTA(path, path, linkOverlay, size, true);
|
||||
}
|
||||
|
||||
return icon;
|
||||
}
|
||||
|
||||
public static Icon GetIconSTA(string path, string resolvedPath, bool linkOverlay, IconSize size, bool isFolder)
|
||||
{
|
||||
Icon icon = null;
|
||||
if (Thread.CurrentThread.GetApartmentState() == ApartmentState.STA)
|
||||
{
|
||||
icon = GetIcon(path, resolvedPath, linkOverlay, size, isFolder);
|
||||
}
|
||||
else
|
||||
{
|
||||
Thread staThread = new(new ParameterizedThreadStart(StaThreadMethod));
|
||||
void StaThreadMethod(object obj)
|
||||
{
|
||||
icon = GetIcon(path, resolvedPath, linkOverlay, size, isFolder);
|
||||
}
|
||||
|
||||
staThread.SetApartmentState(ApartmentState.STA);
|
||||
staThread.Start(icon);
|
||||
staThread.Join();
|
||||
}
|
||||
|
||||
return icon;
|
||||
}
|
||||
|
||||
public static Icon AddIconOverlay(Icon originalIcon, Icon overlay)
|
||||
{
|
||||
Icon icon = null;
|
||||
if (originalIcon != null)
|
||||
{
|
||||
using Bitmap target = new(originalIcon.Width, originalIcon.Height, PixelFormat.Format32bppArgb);
|
||||
using Graphics graphics = Graphics.FromImage(target);
|
||||
graphics.DrawIcon(originalIcon, 0, 0);
|
||||
graphics.DrawIcon(overlay, new(0, 0, originalIcon.Width + 2, originalIcon.Height + 2));
|
||||
target.MakeTransparent(target.GetPixel(1, 1));
|
||||
IntPtr hIcon = target.GetHicon();
|
||||
icon = (Icon)Icon.FromHandle(hIcon).Clone();
|
||||
NativeMethods.User32DestroyIcon(hIcon);
|
||||
}
|
||||
|
||||
return icon;
|
||||
}
|
||||
|
||||
private static ConcurrentDictionary<string, Icon> DictIconCache(bool isMainMenu)
|
||||
{
|
||||
if (isMainMenu)
|
||||
{
|
||||
return DictIconCacheMainMenu;
|
||||
}
|
||||
else
|
||||
{
|
||||
return DictIconCacheSubMenus;
|
||||
}
|
||||
}
|
||||
|
||||
private static bool IsExtensionWithSameIcon(string fileExtension)
|
||||
{
|
||||
bool isExtensionWithSameIcon = true;
|
||||
List<string> extensionsWithDiffIcons = new() { string.Empty, ".EXE", ".LNK", ".ICO", ".URL" };
|
||||
if (extensionsWithDiffIcons.Contains(fileExtension.ToUpperInvariant()))
|
||||
{
|
||||
isExtensionWithSameIcon = false;
|
||||
}
|
||||
|
||||
return isExtensionWithSameIcon;
|
||||
}
|
||||
|
||||
private static Icon GetIcon(string path, string resolvedPath, bool linkOverlay, IconSize size, bool isFolder)
|
||||
{
|
||||
Icon icon;
|
||||
if (Path.GetExtension(path).Equals(".ico", StringComparison.InvariantCultureIgnoreCase))
|
||||
{
|
||||
icon = Icon.ExtractAssociatedIcon(path);
|
||||
}
|
||||
else if (Path.GetExtension(resolvedPath).Equals(".ico", StringComparison.InvariantCultureIgnoreCase) &&
|
||||
File.Exists(resolvedPath))
|
||||
{
|
||||
icon = Icon.ExtractAssociatedIcon(resolvedPath);
|
||||
if (linkOverlay)
|
||||
{
|
||||
icon = AddIconOverlay(icon, Properties.Resources.LinkArrow);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
NativeMethods.SHFILEINFO shFileInfo = default;
|
||||
uint flags = GetFlags(linkOverlay, size);
|
||||
uint attribute = isFolder ? NativeMethods.FileAttributeDirectory : NativeMethods.FileAttributeNormal;
|
||||
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)
|
||||
{
|
||||
uint flags = NativeMethods.ShgfiIcon | NativeMethods.ShgfiSYSICONINDEX;
|
||||
if (linkOverlay)
|
||||
{
|
||||
flags += NativeMethods.ShgfiLINKOVERLAY;
|
||||
}
|
||||
|
||||
if (size == IconSize.Small)
|
||||
{
|
||||
flags += NativeMethods.ShgfiSMALLICON;
|
||||
}
|
||||
else
|
||||
{
|
||||
flags += NativeMethods.ShgfiLARGEICON;
|
||||
}
|
||||
|
||||
return flags;
|
||||
}
|
||||
|
||||
private static Icon GetIcon(
|
||||
string path, bool linkOverlay, NativeMethods.SHFILEINFO shFileInfo, IntPtr imageList)
|
||||
{
|
||||
Icon icon = null;
|
||||
if (imageList != IntPtr.Zero)
|
||||
{
|
||||
IntPtr hIcon;
|
||||
if (linkOverlay)
|
||||
{
|
||||
hIcon = shFileInfo.hIcon;
|
||||
}
|
||||
else
|
||||
{
|
||||
hIcon = NativeMethods.ImageList_GetIcon(
|
||||
imageList, shFileInfo.iIcon, NativeMethods.IldTransparent);
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
icon = (Icon)Icon.FromHandle(hIcon).Clone();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.Warn($"path:'{path}'", ex);
|
||||
}
|
||||
|
||||
if (!linkOverlay)
|
||||
{
|
||||
NativeMethods.User32DestroyIcon(hIcon);
|
||||
}
|
||||
|
||||
NativeMethods.User32DestroyIcon(shFileInfo.hIcon);
|
||||
}
|
||||
|
||||
return icon;
|
||||
}
|
||||
}
|
||||
}
|
||||
96
FSI.BT.Tools/SystemTrayMenu/Utilities/FolderOptions.cs
Normal file
96
FSI.BT.Tools/SystemTrayMenu/Utilities/FolderOptions.cs
Normal file
@@ -0,0 +1,96 @@
|
||||
// <copyright file="FolderOptions.cs" company="PlaceholderCompany">
|
||||
// Copyright (c) PlaceholderCompany. All rights reserved.
|
||||
// </copyright>
|
||||
|
||||
namespace FSI.BT.Tools.SystemTrayMenu.Utilities
|
||||
{
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Reflection;
|
||||
using System.Runtime.InteropServices;
|
||||
using Shell32;
|
||||
using FSI.BT.Tools.SystemTrayMenu.DataClasses;
|
||||
using FSI.BT.Tools.Global.Utilities;
|
||||
|
||||
internal static class FolderOptions
|
||||
{
|
||||
private static bool hideHiddenEntries;
|
||||
private static bool hideSystemEntries;
|
||||
private static IShellDispatch4 iShellDispatch4;
|
||||
|
||||
internal static void Initialize()
|
||||
{
|
||||
try
|
||||
{
|
||||
iShellDispatch4 = (IShellDispatch4)Activator.CreateInstance(
|
||||
Type.GetTypeFromProgID("Shell.Application"));
|
||||
|
||||
// Using SHGetSetSettings would be much better in performance but the results are not accurate.
|
||||
// We have to go for the shell interface in order to receive the correct settings:
|
||||
// https://docs.microsoft.com/en-us/windows/win32/shell/ishelldispatch4-getsetting
|
||||
const int SSF_SHOWALLOBJECTS = 0x00000001;
|
||||
hideHiddenEntries = !iShellDispatch4.GetSetting(
|
||||
SSF_SHOWALLOBJECTS);
|
||||
|
||||
const int SSF_SHOWSUPERHIDDEN = 0x00040000;
|
||||
hideSystemEntries = !iShellDispatch4.GetSetting(
|
||||
SSF_SHOWSUPERHIDDEN);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
if (ex is ArgumentException ||
|
||||
ex is NotSupportedException ||
|
||||
ex is TargetInvocationException ||
|
||||
ex is MethodAccessException ||
|
||||
ex is MemberAccessException ||
|
||||
ex is InvalidComObjectException ||
|
||||
ex is MissingMethodException ||
|
||||
ex is COMException ||
|
||||
ex is TypeLoadException)
|
||||
{
|
||||
Log.Warn("Get Shell COM instance failed", ex);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal static bool IsHidden(RowData rowData)
|
||||
{
|
||||
bool isDirectoryToHide = false;
|
||||
if (rowData.Path.Length >= 260)
|
||||
{
|
||||
Log.Info($"path too long (>=260):'{rowData.Path}'");
|
||||
return isDirectoryToHide;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
FileAttributes attributes = File.GetAttributes(rowData.Path);
|
||||
rowData.HiddenEntry = attributes.HasFlag(FileAttributes.Hidden);
|
||||
bool systemEntry = attributes.HasFlag(
|
||||
FileAttributes.Hidden | FileAttributes.System);
|
||||
if (Global.Vars.SystemTrayMenuSettings.SystemSettingsShowHiddenFiles)
|
||||
{
|
||||
if ((hideHiddenEntries && rowData.HiddenEntry) ||
|
||||
(hideSystemEntries && systemEntry))
|
||||
{
|
||||
isDirectoryToHide = true;
|
||||
}
|
||||
}
|
||||
else if (rowData.HiddenEntry && Global.Vars.SystemTrayMenuSettings.NeverShowHiddenFiles)
|
||||
{
|
||||
isDirectoryToHide = true;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.Warn($"path:'{rowData.Path}'", ex);
|
||||
}
|
||||
|
||||
return isDirectoryToHide;
|
||||
}
|
||||
}
|
||||
}
|
||||
24
FSI.BT.Tools/SystemTrayMenu/Utilities/FormsExtensions.cs
Normal file
24
FSI.BT.Tools/SystemTrayMenu/Utilities/FormsExtensions.cs
Normal file
@@ -0,0 +1,24 @@
|
||||
// <copyright file="FormsExtensions.cs" company="PlaceholderCompany">
|
||||
// Copyright (c) PlaceholderCompany. All rights reserved.
|
||||
// </copyright>
|
||||
|
||||
namespace FSI.BT.Tools.SystemTrayMenu.Utilities
|
||||
{
|
||||
using System;
|
||||
using System.Windows.Forms;
|
||||
|
||||
internal static class FormsExtensions
|
||||
{
|
||||
public static void HandleInvoke(this Control instance, Action action)
|
||||
{
|
||||
if (instance.InvokeRequired)
|
||||
{
|
||||
instance.Invoke(action);
|
||||
}
|
||||
else
|
||||
{
|
||||
action();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
// <copyright file="GenerateDriveShortcuts.cs" company="PlaceholderCompany">
|
||||
// Copyright (c) PlaceholderCompany. All rights reserved.
|
||||
// </copyright>
|
||||
|
||||
namespace FSI.BT.Tools.SystemTrayMenu.Utilities
|
||||
{
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using FSI.BT.Tools.Global.Utilities;
|
||||
using IWshRuntimeLibrary;
|
||||
|
||||
internal class GenerateDriveShortcuts
|
||||
{
|
||||
public static void Start()
|
||||
{
|
||||
List<char> driveNamesToRemove = "ABCDEFGHIJKLMNOPQRSTUVWXYZ".ToCharArray().ToList();
|
||||
|
||||
DriveInfo[] driveInfos = DriveInfo.GetDrives();
|
||||
foreach (DriveInfo driveInfo in driveInfos)
|
||||
{
|
||||
driveNamesToRemove.Remove(driveInfo.Name[0]);
|
||||
string linkPath = GetLinkPathFromDriveName(driveInfo.Name[..1]);
|
||||
if (!System.IO.File.Exists(linkPath))
|
||||
{
|
||||
CreateShortcut(linkPath, driveInfo.Name);
|
||||
}
|
||||
}
|
||||
|
||||
foreach (char driveName in driveNamesToRemove)
|
||||
{
|
||||
string possibleShortcut = GetLinkPathFromDriveName(driveName.ToString());
|
||||
|
||||
try
|
||||
{
|
||||
System.IO.File.Delete(possibleShortcut);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.Warn($"Could not delete shortcut at path:'{possibleShortcut}'", ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void CreateShortcut(string linkPath, string targetPath)
|
||||
{
|
||||
WshShell shell = new();
|
||||
IWshShortcut shortcut = (IWshShortcut)shell.CreateShortcut(linkPath);
|
||||
shortcut.Description = "Generated by SystemTrayMenu";
|
||||
shortcut.TargetPath = targetPath;
|
||||
|
||||
try
|
||||
{
|
||||
shortcut.Save();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.Warn($"Could not create shortcut at path:'{linkPath}'", ex);
|
||||
}
|
||||
}
|
||||
|
||||
private static string GetLinkPathFromDriveName(string driveName)
|
||||
{
|
||||
return Path.Combine(Config.Path, $" {driveName} .lnk");
|
||||
}
|
||||
}
|
||||
}
|
||||
97
FSI.BT.Tools/SystemTrayMenu/Utilities/SingleAppInstance.cs
Normal file
97
FSI.BT.Tools/SystemTrayMenu/Utilities/SingleAppInstance.cs
Normal file
@@ -0,0 +1,97 @@
|
||||
// <copyright file="SingleAppInstance.cs" company="PlaceholderCompany">
|
||||
// Copyright (c) PlaceholderCompany. All rights reserved.
|
||||
// </copyright>
|
||||
|
||||
namespace FSI.BT.Tools.SystemTrayMenu.Utilities
|
||||
{
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Windows.Forms;
|
||||
using FSI.BT.Tools.Global.UserInterface.HotkeyTextboxControl;
|
||||
using FSI.BT.Tools.Global.Utilities;
|
||||
using WindowsInput;
|
||||
|
||||
internal static class SingleAppInstance
|
||||
{
|
||||
internal static bool Initialize()
|
||||
{
|
||||
bool success = true;
|
||||
|
||||
try
|
||||
{
|
||||
foreach (Process p in Process.GetProcessesByName(
|
||||
Process.GetCurrentProcess().ProcessName).
|
||||
Where(s => s.Id != Environment.ProcessId))
|
||||
{
|
||||
if (Global.Vars.SystemTrayMenuSettings.SendHotkeyInsteadKillOtherInstances)
|
||||
{
|
||||
Keys modifiers = HotkeyControl.HotkeyModifiersFromString(Global.Vars.SystemTrayMenuSettings.HotKey);
|
||||
Keys hotkey = HotkeyControl.HotkeyFromString(Global.Vars.SystemTrayMenuSettings.HotKey);
|
||||
|
||||
try
|
||||
{
|
||||
List<VirtualKeyCode> virtualKeyCodesModifiers = new();
|
||||
foreach (string key in modifiers.ToString().ToUpperInvariant().Split(", "))
|
||||
{
|
||||
if (key == "NONE")
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
VirtualKeyCode virtualKeyCode = VirtualKeyCode.LWIN;
|
||||
virtualKeyCode = key switch
|
||||
{
|
||||
"ALT" => VirtualKeyCode.MENU,
|
||||
_ => (VirtualKeyCode)Enum.Parse(
|
||||
typeof(VirtualKeyCode), key.ToUpperInvariant()),
|
||||
};
|
||||
virtualKeyCodesModifiers.Add(virtualKeyCode);
|
||||
}
|
||||
|
||||
VirtualKeyCode virtualKeyCodeHotkey = 0;
|
||||
if (Enum.IsDefined(typeof(VirtualKeyCode), (int)hotkey))
|
||||
{
|
||||
virtualKeyCodeHotkey = (VirtualKeyCode)(int)hotkey;
|
||||
}
|
||||
|
||||
new InputSimulator().Keyboard.ModifiedKeyStroke(virtualKeyCodesModifiers, virtualKeyCodeHotkey);
|
||||
|
||||
success = false;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.Warn($"Send hoktey {Global.Vars.SystemTrayMenuSettings.HotKey} to other instance failed", ex);
|
||||
}
|
||||
}
|
||||
|
||||
if (!Global.Vars.SystemTrayMenuSettings.SendHotkeyInsteadKillOtherInstances)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!p.CloseMainWindow())
|
||||
{
|
||||
p.Kill();
|
||||
}
|
||||
|
||||
p.WaitForExit();
|
||||
p.Close();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.Error("Run as single instance failed", ex);
|
||||
success = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.Error("Run as single instance failed", ex);
|
||||
}
|
||||
|
||||
return success;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user