[Launcher] Categorize Lnk files in program plugin correctly as per the target file type (#6348)

* Updated UnregisteredApps code

* Added file type checking code and Folder and File classifications

* Added more file formats

* Removed run as admin for lnk folders

* Added script files as executable and changed hashset to case insensitive

* Removed runasadmin for generic files

* Removed FileTypes enum

* Extended ApplicationTypes enum

* Fix file format error

* Cleaned use of ApplicationType enum to public and match AppType and used ApplicationType in OnAppRenamed

* Modify tests to use ApplicationType enum

* Added tests for new App types

* Modified dummy appref

* Mock Directory.Exists and add tests for GetAppTypeFromPath

* Combined tests
This commit is contained in:
Arjun Balgovind
2020-09-10 15:06:37 -07:00
committed by GitHub
parent ab8bec8866
commit 82e1be2839
8 changed files with 287 additions and 59 deletions

View File

@@ -52,7 +52,7 @@ namespace Microsoft.Plugin.Program.Programs
public string Location => ParentDirectory;
public uint AppType { get; set; }
public ApplicationType AppType { get; set; }
// Wrappers for File Operations
public static IFileVersionInfoWrapper FileVersionInfoWrapper { get; set; } = new FileVersionInfoWrapper();
@@ -61,20 +61,26 @@ namespace Microsoft.Plugin.Program.Programs
public static IShellLinkHelper Helper { get; set; } = new ShellLinkHelper();
public static IDirectoryWrapper DirectoryWrapper { get; set; } = new DirectoryWrapper();
private const string ShortcutExtension = "lnk";
private const string ApplicationReferenceExtension = "appref-ms";
private const string ExeExtension = "exe";
private const string InternetShortcutExtension = "url";
private static readonly HashSet<string> ExecutableApplicationExtensions = new HashSet<string>(StringComparer.OrdinalIgnoreCase) { "exe", "bat", "bin", "com", "msc", "msi", "cmd", "ps1", "job", "msp", "mst", "sct", "ws", "wsh", "wsf" };
private const string ProxyWebApp = "_proxy.exe";
private const string AppIdArgument = "--app-id";
private enum ApplicationTypes
public enum ApplicationType
{
WEB_APPLICATION = 0,
INTERNET_SHORTCUT_APPLICATION = 1,
WIN32_APPLICATION = 2,
RUN_COMMAND = 3,
WebApplication = 0,
InternetShortcutApplication = 1,
Win32Application = 2,
ShortcutApplication = 3,
ApprefApplication = 4,
RunCommand = 5,
Folder = 6,
GenericFile = 7,
}
// Function to calculate the score of a result
@@ -106,7 +112,7 @@ namespace Microsoft.Plugin.Program.Programs
}
// Set the subtitle to 'Web Application'
AppType = (uint)ApplicationTypes.WEB_APPLICATION;
AppType = ApplicationType.WebApplication;
string[] subqueries = query?.Split() ?? Array.Empty<string>();
bool nameContainsQuery = false;
@@ -132,22 +138,30 @@ namespace Microsoft.Plugin.Program.Programs
// Function to set the subtitle based on the Type of application
private string SetSubtitle()
{
if (AppType == (uint)ApplicationTypes.WIN32_APPLICATION)
if (AppType == ApplicationType.Win32Application || AppType == ApplicationType.ShortcutApplication || AppType == ApplicationType.ApprefApplication)
{
return Properties.Resources.powertoys_run_plugin_program_win32_application;
}
else if (AppType == (uint)ApplicationTypes.INTERNET_SHORTCUT_APPLICATION)
else if (AppType == ApplicationType.InternetShortcutApplication)
{
return Properties.Resources.powertoys_run_plugin_program_internet_shortcut_application;
}
else if (AppType == (uint)ApplicationTypes.WEB_APPLICATION)
else if (AppType == ApplicationType.WebApplication)
{
return Properties.Resources.powertoys_run_plugin_program_web_application;
}
else if (AppType == (uint)ApplicationTypes.RUN_COMMAND)
else if (AppType == ApplicationType.RunCommand)
{
return Properties.Resources.powertoys_run_plugin_program_run_command;
}
else if (AppType == ApplicationType.Folder)
{
return Properties.Resources.powertoys_run_plugin_program_folder_type;
}
else if (AppType == ApplicationType.GenericFile)
{
return Properties.Resources.powertoys_run_plugin_program_generic_file_type;
}
else
{
return string.Empty;
@@ -156,7 +170,7 @@ namespace Microsoft.Plugin.Program.Programs
public bool QueryEqualsNameForRunCommands(string query)
{
if (query != null && AppType == (uint)ApplicationTypes.RUN_COMMAND
if (query != null && AppType == ApplicationType.RunCommand
&& !query.Equals(Name, StringComparison.OrdinalIgnoreCase))
{
return false;
@@ -240,7 +254,7 @@ namespace Microsoft.Plugin.Program.Programs
var contextMenus = new List<ContextMenuResult>();
if (AppType != (uint)ApplicationTypes.INTERNET_SHORTCUT_APPLICATION)
if (AppType != ApplicationType.InternetShortcutApplication && AppType != ApplicationType.Folder && AppType != ApplicationType.GenericFile)
{
contextMenus.Add(new ContextMenuResult
{
@@ -330,7 +344,7 @@ namespace Microsoft.Plugin.Program.Programs
Description = string.Empty,
Valid = true,
Enabled = true,
AppType = (uint)ApplicationTypes.WIN32_APPLICATION,
AppType = ApplicationType.Win32Application,
};
return p;
}
@@ -394,7 +408,7 @@ namespace Microsoft.Plugin.Program.Programs
ParentDirectory = Directory.GetParent(path).FullName,
Valid = true,
Enabled = true,
AppType = (uint)ApplicationTypes.INTERNET_SHORTCUT_APPLICATION,
AppType = ApplicationType.InternetShortcutApplication,
};
return p;
}
@@ -421,14 +435,11 @@ namespace Microsoft.Plugin.Program.Programs
if (!string.IsNullOrEmpty(target))
{
var extension = Extension(target);
if (extension == ExeExtension && File.Exists(target))
if (File.Exists(target) || Directory.Exists(target))
{
program.LnkResolvedPath = program.FullPath;
program.FullPath = Path.GetFullPath(target).ToLower(CultureInfo.CurrentCulture);
program.ExecutableName = Path.GetFileName(target);
program.HasArguments = Helper.HasArguments;
program.Arguments = Helper.Arguments;
program.AppType = GetAppTypeFromPath(target);
var description = Helper.Description;
if (!string.IsNullOrEmpty(description))
@@ -494,6 +505,43 @@ namespace Microsoft.Plugin.Program.Programs
}
}
// Function to get the application type, given the path to the application
public static ApplicationType GetAppTypeFromPath(string path)
{
if (path == null)
{
throw new ArgumentNullException(nameof(path));
}
string extension = Extension(path);
ApplicationType appType = ApplicationType.GenericFile;
if (ExecutableApplicationExtensions.Contains(extension))
{
appType = ApplicationType.Win32Application;
}
else if (extension.Equals(ShortcutExtension, StringComparison.OrdinalIgnoreCase))
{
appType = ApplicationType.ShortcutApplication;
}
else if (extension.Equals(ApplicationReferenceExtension, StringComparison.OrdinalIgnoreCase))
{
appType = ApplicationType.ApprefApplication;
}
else if (extension.Equals(InternetShortcutExtension, StringComparison.OrdinalIgnoreCase))
{
appType = ApplicationType.InternetShortcutApplication;
}
// If the path exists, check if it is a directory
else if (DirectoryWrapper.Exists(path))
{
appType = ApplicationType.Folder;
}
return appType;
}
// Function to get the Win32 application, given the path to the application
public static Win32Program GetAppFromPath(string path)
{
@@ -503,26 +551,23 @@ namespace Microsoft.Plugin.Program.Programs
}
Win32Program app = null;
const string exeExtension = ".exe";
const string lnkExtension = ".lnk";
const string urlExtenion = ".url";
const string apprefExtension = ".appref-ms";
string extension = Path.GetExtension(path);
ApplicationType appType = GetAppTypeFromPath(path);
if (extension.Equals(exeExtension, StringComparison.OrdinalIgnoreCase))
if (appType == ApplicationType.Win32Application)
{
app = ExeProgram(path);
}
else if (extension.Equals(lnkExtension, StringComparison.OrdinalIgnoreCase))
else if (appType == ApplicationType.ShortcutApplication)
{
app = LnkProgram(path);
}
else if (extension.Equals(apprefExtension, StringComparison.OrdinalIgnoreCase))
else if (appType == ApplicationType.ApprefApplication)
{
app = CreateWin32Program(path);
app.AppType = ApplicationType.ApprefApplication;
}
else if (extension.Equals(urlExtenion, StringComparison.OrdinalIgnoreCase))
else if (appType == ApplicationType.InternetShortcutApplication)
{
app = InternetShortcutProgram(path);
}
@@ -626,13 +671,13 @@ namespace Microsoft.Plugin.Program.Programs
var paths = listToAdd.Distinct().ToArray();
var programs1 = paths.AsParallel().Where(p => Extension(p) == ExeExtension).Select(ExeProgram);
var programs2 = paths.AsParallel().Where(p => Extension(p) == ShortcutExtension).Select(ExeProgram);
var programs1 = paths.AsParallel().Where(p => ExecutableApplicationExtensions.Contains(Extension(p))).Select(ExeProgram);
var programs2 = paths.AsParallel().Where(p => Extension(p) == ShortcutExtension).Select(LnkProgram);
var programs3 = from p in paths.AsParallel()
let e = Extension(p)
where e != ShortcutExtension && e != ExeExtension
where e != ShortcutExtension && !ExecutableApplicationExtensions.Contains(e)
select CreateWin32Program(p);
return programs1.Concat(programs2).Concat(programs3);
return programs1.Concat(programs2).Where(p => p.Valid).Concat(programs3).Where(p => p.Valid);
}
// Function to obtain the list of applications, the locations of which have been added to the env variable PATH
@@ -662,14 +707,14 @@ namespace Microsoft.Plugin.Program.Programs
var programs1 = allPaths.AsParallel().Where(p => Extension(p).Equals(ShortcutExtension, StringComparison.OrdinalIgnoreCase)).Select(LnkProgram);
var programs2 = allPaths.AsParallel().Where(p => Extension(p).Equals(ApplicationReferenceExtension, StringComparison.OrdinalIgnoreCase)).Select(CreateWin32Program);
var programs3 = allPaths.AsParallel().Where(p => Extension(p).Equals(InternetShortcutExtension, StringComparison.OrdinalIgnoreCase)).Select(InternetShortcutProgram);
var programs4 = allPaths.AsParallel().Where(p => Extension(p).Equals(ExeExtension, StringComparison.OrdinalIgnoreCase)).Select(ExeProgram);
var programs4 = allPaths.AsParallel().Where(p => ExecutableApplicationExtensions.Contains(Extension(p))).Select(ExeProgram);
var allPrograms = programs1.Concat(programs2).Where(p => p.Valid)
.Concat(programs3).Where(p => p.Valid)
.Concat(programs4).Where(p => p.Valid)
.Select(p =>
{
p.AppType = (uint)ApplicationTypes.RUN_COMMAND;
p.AppType = ApplicationType.RunCommand;
return p;
});
@@ -696,7 +741,7 @@ namespace Microsoft.Plugin.Program.Programs
var programs1 = paths.AsParallel().Where(p => Extension(p).Equals(ShortcutExtension, StringComparison.OrdinalIgnoreCase)).Select(LnkProgram);
var programs2 = paths.AsParallel().Where(p => Extension(p).Equals(ApplicationReferenceExtension, StringComparison.OrdinalIgnoreCase)).Select(CreateWin32Program);
var programs3 = paths.AsParallel().Where(p => Extension(p).Equals(InternetShortcutExtension, StringComparison.OrdinalIgnoreCase)).Select(InternetShortcutProgram);
var programs4 = paths.AsParallel().Where(p => Extension(p).Equals(ExeExtension, StringComparison.OrdinalIgnoreCase)).Select(ExeProgram);
var programs4 = paths.AsParallel().Where(p => ExecutableApplicationExtensions.Contains(Extension(p))).Select(ExeProgram);
return programs1.Concat(programs2).Where(p => p.Valid)
.Concat(programs3).Where(p => p.Valid)
@@ -858,7 +903,7 @@ namespace Microsoft.Plugin.Program.Programs
// Deduplication code
public static Win32Program[] DeduplicatePrograms(ParallelQuery<Win32Program> programs)
{
var uniqueExePrograms = programs.Where(x => !(string.IsNullOrEmpty(x.LnkResolvedPath) && (Extension(x.FullPath) == ExeExtension) && !(x.AppType == (uint)ApplicationTypes.RUN_COMMAND)));
var uniqueExePrograms = programs.Where(x => !(string.IsNullOrEmpty(x.LnkResolvedPath) && ExecutableApplicationExtensions.Contains(Extension(x.FullPath)) && !(x.AppType == ApplicationType.RunCommand)));
var uniquePrograms = uniqueExePrograms.Distinct(new RemoveDuplicatesComparer());
return uniquePrograms.ToArray();
}