From 979e0d0d6f0129ede8968368c154f19f25590497 Mon Sep 17 00:00:00 2001 From: iksi4prs Date: Sat, 28 Oct 2023 19:53:11 +0300 Subject: [PATCH 1/3] fixed shell icons, which didn't work becauase IPathService and System.IO.Path return different values for GetExtension --- .../IPathService.cs | 2 ++ .../Implementations/EnvironmentPathService.cs | 2 ++ .../Interfaces/IEnvironmentPathService.cs | 2 ++ src/Camelot.Services/PathService.cs | 17 ++++++++++ .../ShellIcons/WindowsIconTypes.cs | 13 ++++++-- .../ShellIcons/WindowsShellIconsService.cs | 32 ++++++++----------- .../ShellIcons/WindowsShellLinksService.cs | 3 +- .../WinApi/ShellIcon.cs | 8 +++-- .../WinApi/ShellLinkResolver.cs | 2 +- 9 files changed, 54 insertions(+), 27 deletions(-) diff --git a/src/Camelot.Services.Abstractions/IPathService.cs b/src/Camelot.Services.Abstractions/IPathService.cs index 18068753..1513acdd 100644 --- a/src/Camelot.Services.Abstractions/IPathService.cs +++ b/src/Camelot.Services.Abstractions/IPathService.cs @@ -18,6 +18,8 @@ public interface IPathService string GetExtension(string path); + bool IsExtension(string extension); + string RightTrimPathSeparators(string path); string LeftTrimPathSeparators(string relativePath); diff --git a/src/Camelot.Services.Environment/Implementations/EnvironmentPathService.cs b/src/Camelot.Services.Environment/Implementations/EnvironmentPathService.cs index 983f69b2..888a09d7 100644 --- a/src/Camelot.Services.Environment/Implementations/EnvironmentPathService.cs +++ b/src/Camelot.Services.Environment/Implementations/EnvironmentPathService.cs @@ -16,4 +16,6 @@ public class EnvironmentPathService : IEnvironmentPathService public string GetFileName(string path) => Path.GetFileName(path); public string GetExtension(string path) => Path.GetExtension(path); + + public char GetDirectorySeparator() => Path.DirectorySeparatorChar; } \ No newline at end of file diff --git a/src/Camelot.Services.Environment/Interfaces/IEnvironmentPathService.cs b/src/Camelot.Services.Environment/Interfaces/IEnvironmentPathService.cs index 2e129149..2dbd1f1f 100644 --- a/src/Camelot.Services.Environment/Interfaces/IEnvironmentPathService.cs +++ b/src/Camelot.Services.Environment/Interfaces/IEnvironmentPathService.cs @@ -13,4 +13,6 @@ public interface IEnvironmentPathService string GetFileName(string path); string GetExtension(string path); + + char GetDirectorySeparator(); } \ No newline at end of file diff --git a/src/Camelot.Services/PathService.cs b/src/Camelot.Services/PathService.cs index 53ca2b54..9abb6c20 100644 --- a/src/Camelot.Services/PathService.cs +++ b/src/Camelot.Services/PathService.cs @@ -63,6 +63,12 @@ public string GetFileName(string path) return string.IsNullOrEmpty(fileName) ? path : fileName; } + /// + /// Returns the extension of the given path, without the prefix of dot. + /// This is intentionally returns different result than + /// + /// public string GetExtension(string path) { if (path.StartsWith(".")) @@ -82,6 +88,17 @@ public string GetExtension(string path) return extension.StartsWith(".") ? extension[1..] : extension; } + public bool IsExtension(string extension) + { + if (string.IsNullOrWhiteSpace(extension)) + return false; + if (extension.Contains(".")) + return false; + if (extension.Contains(_environmentPathService.GetDirectorySeparator())) + return false; + return true; + } + public string RightTrimPathSeparators(string path) => path == "/" ? path : path.TrimEnd('/').TrimEnd('\\'); public string LeftTrimPathSeparators(string relativePath) => relativePath.TrimStart('/').TrimStart('\\'); diff --git a/src/Camelot.ViewModels.Windows/ShellIcons/WindowsIconTypes.cs b/src/Camelot.ViewModels.Windows/ShellIcons/WindowsIconTypes.cs index d75686ee..d8e1b5ec 100644 --- a/src/Camelot.ViewModels.Windows/ShellIcons/WindowsIconTypes.cs +++ b/src/Camelot.ViewModels.Windows/ShellIcons/WindowsIconTypes.cs @@ -8,13 +8,20 @@ public static bool IsIconThatRequiresExtract(string fileName, string extension) { throw new ArgumentNullException(nameof(fileName)); } - + if (string.IsNullOrEmpty(extension)) + { + throw new ArgumentNullException(nameof(extension)); + } + if (extension.StartsWith(".")) + { + // As per stanards of this project, extension don't have dot prefix. + throw new ArgumentOutOfRangeException(nameof(extension)); + } if (fileName.Contains('?') || fileName.Contains(',')) { return true; // icon in indexed resource } - - var extensionsOfIcoFiles = new List { ".ico", ".exe", ".dll" , ".cpl", ".appref-ms", ".msc" }; + var extensionsOfIcoFiles = new List { "ico", "exe", "dll" , "cpl", "appref-ms", "msc" }; return extensionsOfIcoFiles.Contains(extension); } diff --git a/src/Camelot.ViewModels.Windows/ShellIcons/WindowsShellIconsService.cs b/src/Camelot.ViewModels.Windows/ShellIcons/WindowsShellIconsService.cs index 6b5d3c0f..d4e1009b 100644 --- a/src/Camelot.ViewModels.Windows/ShellIcons/WindowsShellIconsService.cs +++ b/src/Camelot.ViewModels.Windows/ShellIcons/WindowsShellIconsService.cs @@ -23,19 +23,14 @@ public WindowsShellIconsService( public ImageModel GetIconForExtension(string extension) { - if (string.IsNullOrEmpty(extension)) + if (!_pathService.IsExtension(extension)) { - throw new ArgumentNullException(nameof(extension)); + throw new ArgumentException(extension, nameof(extension)); } - if (!extension.StartsWith(".")) + if (extension.ToLower() == "lnk") { - throw new ArgumentException(nameof(extension)); - } - - if (extension.ToLower() == ".lnk") - { - throw new ArgumentException("Need to resolve .lnk first"); + throw new ArgumentException("Need to resolve 'lnk' first"); } var iconFilename = ShellIcon.GetIconForExtension(extension); @@ -65,11 +60,10 @@ public ImageModel GetIconForPath(string path) { throw new ArgumentOutOfRangeException(nameof(path)); } - - var ext = GetExtension(path); - if (ext == ".lnk") + var ext = GetExtensionAsLowerCase(path); + if (ext == "lnk") { - throw new ArgumentException("Need to resolve .lnk first"); + throw new ArgumentException("Need to resolve 'lnk' first"); } return LoadIcon(path); @@ -84,7 +78,7 @@ private ImageModel LoadIcon(string path) ImageModel result; - var needsExtract = WindowsIconTypes.IsIconThatRequiresExtract(path, GetExtension(path)); + var needsExtract = WindowsIconTypes.IsIconThatRequiresExtract(path, GetExtensionAsLowerCase(path)); if (needsExtract) { var icon = IconExtractor.ExtractIcon(path); @@ -118,18 +112,18 @@ public ShellIconType GetIconType(string filename) throw new ArgumentNullException(nameof(filename)); } - var ext = GetExtension(filename); - - // next extensions require that the icon will be resolved by full path, + var ext = GetExtensionAsLowerCase(filename); + // Next extensions require that the icon will be resolved by full path, // and not just the extension itself. - var extensionForFullPaths = new[] { ".exe", ".cpl", ".appref-ms", ".msc" }; + // As per stanards of this project, extension don't have dot prefix. + var extensionForFullPaths = new[] { "exe", "cpl", "appref-ms", "msc" }; return extensionForFullPaths.Contains(ext) ? ShellIconType.FullPath : ShellIconType.Extension; } - private string GetExtension(string filename) + private string GetExtensionAsLowerCase(string filename) { return _pathService.GetExtension(filename).ToLower(); } diff --git a/src/Camelot.ViewModels.Windows/ShellIcons/WindowsShellLinksService.cs b/src/Camelot.ViewModels.Windows/ShellIcons/WindowsShellLinksService.cs index 482b8c4c..56e2c5e5 100644 --- a/src/Camelot.ViewModels.Windows/ShellIcons/WindowsShellLinksService.cs +++ b/src/Camelot.ViewModels.Windows/ShellIcons/WindowsShellLinksService.cs @@ -25,8 +25,7 @@ public bool IsShellLink(string path) } var ext = _pathService.GetExtension(path).ToLower(); - - return ext == ".lnk"; + return ext == "lnk"; } public string ResolveLink(string path) diff --git a/src/Camelot.ViewModels.Windows/WinApi/ShellIcon.cs b/src/Camelot.ViewModels.Windows/WinApi/ShellIcon.cs index dcb5d0d5..d17d96d8 100644 --- a/src/Camelot.ViewModels.Windows/WinApi/ShellIcon.cs +++ b/src/Camelot.ViewModels.Windows/WinApi/ShellIcon.cs @@ -11,11 +11,15 @@ public static string GetIconForExtension(string extension) throw new ArgumentNullException(nameof(extension)); } - if (!extension.StartsWith(".")) + if (extension.StartsWith(".")) { - throw new ArgumentException(nameof(extension)); + // As per stanards of this project, extension don't have dot prefix. + throw new ArgumentOutOfRangeException(nameof(extension)); } + // But to work with Windows API, we still need to add dot prefix... + extension = "." + extension; + const Win32.AssocF assocFlag = Win32.AssocF.None; var currentAppIcon = Win32.AssocQueryString(assocFlag, Win32.AssocStr.AppIconRreference, extension); diff --git a/src/Camelot.ViewModels.Windows/WinApi/ShellLinkResolver.cs b/src/Camelot.ViewModels.Windows/WinApi/ShellLinkResolver.cs index 5fa795dc..5f2c0ffd 100644 --- a/src/Camelot.ViewModels.Windows/WinApi/ShellLinkResolver.cs +++ b/src/Camelot.ViewModels.Windows/WinApi/ShellLinkResolver.cs @@ -26,7 +26,7 @@ public string ResolveLink(string path) } var ext = _pathService.GetExtension(path).ToLower(); - if (ext != ".lnk") + if (ext != "lnk") { throw new ArgumentNullException(nameof(path)); } From e8d541eeaad37d0069a32dd7954e95de3c5fb43a Mon Sep 17 00:00:00 2001 From: iksi4prs Date: Sun, 29 Oct 2023 10:40:23 +0200 Subject: [PATCH 2/3] fixed case of win32 api returns invalid value --- .../WinApi/ShellIcon.cs | 27 ++++++++++++++++--- 1 file changed, 24 insertions(+), 3 deletions(-) diff --git a/src/Camelot.ViewModels.Windows/WinApi/ShellIcon.cs b/src/Camelot.ViewModels.Windows/WinApi/ShellIcon.cs index d17d96d8..d7476463 100644 --- a/src/Camelot.ViewModels.Windows/WinApi/ShellIcon.cs +++ b/src/Camelot.ViewModels.Windows/WinApi/ShellIcon.cs @@ -1,4 +1,5 @@ using Camelot.Services.Windows.WinApi; +using System.Diagnostics; namespace Camelot.ViewModels.Windows.WinApi; @@ -23,9 +24,29 @@ public static string GetIconForExtension(string extension) const Win32.AssocF assocFlag = Win32.AssocF.None; var currentAppIcon = Win32.AssocQueryString(assocFlag, Win32.AssocStr.AppIconRreference, extension); - return string.IsNullOrEmpty(currentAppIcon) - ? Win32.AssocQueryString(assocFlag, Win32.AssocStr.DefaultIcon, extension) - : currentAppIcon; + string result; + if (IsValid(currentAppIcon)) + { + result = currentAppIcon; + } + else + { + // fallback to use default + result = Win32.AssocQueryString(assocFlag, Win32.AssocStr.DefaultIcon, extension); + } + return result; + } + + private static bool IsValid(string icon) + { + if (string.IsNullOrEmpty(icon)) + return false; + if (icon.TrimStart().StartsWith("%")) + { + // looks like because of invalid values in registry + return false; + } + return true; } } From 2886257120a76b3860587a6557e19debf9759ca9 Mon Sep 17 00:00:00 2001 From: iksi4prs Date: Wed, 1 Nov 2023 09:51:47 +0200 Subject: [PATCH 3/3] removed args validations --- src/Camelot.Services.Abstractions/IPathService.cs | 2 -- src/Camelot.Services/PathService.cs | 11 ----------- .../ShellIcons/WindowsIconTypes.cs | 5 ----- .../ShellIcons/WindowsShellIconsService.cs | 2 +- src/Camelot.ViewModels.Windows/WinApi/ShellIcon.cs | 6 ------ 5 files changed, 1 insertion(+), 25 deletions(-) diff --git a/src/Camelot.Services.Abstractions/IPathService.cs b/src/Camelot.Services.Abstractions/IPathService.cs index 1513acdd..18068753 100644 --- a/src/Camelot.Services.Abstractions/IPathService.cs +++ b/src/Camelot.Services.Abstractions/IPathService.cs @@ -18,8 +18,6 @@ public interface IPathService string GetExtension(string path); - bool IsExtension(string extension); - string RightTrimPathSeparators(string path); string LeftTrimPathSeparators(string relativePath); diff --git a/src/Camelot.Services/PathService.cs b/src/Camelot.Services/PathService.cs index 9abb6c20..07059e4a 100644 --- a/src/Camelot.Services/PathService.cs +++ b/src/Camelot.Services/PathService.cs @@ -88,17 +88,6 @@ public string GetExtension(string path) return extension.StartsWith(".") ? extension[1..] : extension; } - public bool IsExtension(string extension) - { - if (string.IsNullOrWhiteSpace(extension)) - return false; - if (extension.Contains(".")) - return false; - if (extension.Contains(_environmentPathService.GetDirectorySeparator())) - return false; - return true; - } - public string RightTrimPathSeparators(string path) => path == "/" ? path : path.TrimEnd('/').TrimEnd('\\'); public string LeftTrimPathSeparators(string relativePath) => relativePath.TrimStart('/').TrimStart('\\'); diff --git a/src/Camelot.ViewModels.Windows/ShellIcons/WindowsIconTypes.cs b/src/Camelot.ViewModels.Windows/ShellIcons/WindowsIconTypes.cs index d8e1b5ec..1a90a128 100644 --- a/src/Camelot.ViewModels.Windows/ShellIcons/WindowsIconTypes.cs +++ b/src/Camelot.ViewModels.Windows/ShellIcons/WindowsIconTypes.cs @@ -12,11 +12,6 @@ public static bool IsIconThatRequiresExtract(string fileName, string extension) { throw new ArgumentNullException(nameof(extension)); } - if (extension.StartsWith(".")) - { - // As per stanards of this project, extension don't have dot prefix. - throw new ArgumentOutOfRangeException(nameof(extension)); - } if (fileName.Contains('?') || fileName.Contains(',')) { return true; // icon in indexed resource diff --git a/src/Camelot.ViewModels.Windows/ShellIcons/WindowsShellIconsService.cs b/src/Camelot.ViewModels.Windows/ShellIcons/WindowsShellIconsService.cs index d4e1009b..d8b09320 100644 --- a/src/Camelot.ViewModels.Windows/ShellIcons/WindowsShellIconsService.cs +++ b/src/Camelot.ViewModels.Windows/ShellIcons/WindowsShellIconsService.cs @@ -23,7 +23,7 @@ public WindowsShellIconsService( public ImageModel GetIconForExtension(string extension) { - if (!_pathService.IsExtension(extension)) + if (string.IsNullOrEmpty(extension)) { throw new ArgumentException(extension, nameof(extension)); } diff --git a/src/Camelot.ViewModels.Windows/WinApi/ShellIcon.cs b/src/Camelot.ViewModels.Windows/WinApi/ShellIcon.cs index d7476463..bc3a6d9a 100644 --- a/src/Camelot.ViewModels.Windows/WinApi/ShellIcon.cs +++ b/src/Camelot.ViewModels.Windows/WinApi/ShellIcon.cs @@ -12,12 +12,6 @@ public static string GetIconForExtension(string extension) throw new ArgumentNullException(nameof(extension)); } - if (extension.StartsWith(".")) - { - // As per stanards of this project, extension don't have dot prefix. - throw new ArgumentOutOfRangeException(nameof(extension)); - } - // But to work with Windows API, we still need to add dot prefix... extension = "." + extension;