[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
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 287 additions and 59 deletions

View File

@ -8,6 +8,7 @@ using System.Linq;
using Moq;
using NUnit.Framework;
using Wox.Infrastructure;
using Wox.Infrastructure.FileSystemHelper;
using Wox.Plugin;
namespace Microsoft.Plugin.Program.UnitTests.Programs
@ -23,7 +24,7 @@ namespace Microsoft.Plugin.Program.UnitTests.Programs
ExecutableName = "notepad.exe",
FullPath = "c:\\windows\\system32\\notepad.exe",
LnkResolvedPath = "c:\\users\\powertoys\\appdata\\roaming\\microsoft\\windows\\start menu\\programs\\accessories\\notepad.lnk",
AppType = 2,
AppType = Win32Program.ApplicationType.Win32Application,
};
private static readonly Win32Program _notepadUsers = new Win32Program
@ -32,7 +33,7 @@ namespace Microsoft.Plugin.Program.UnitTests.Programs
ExecutableName = "notepad.exe",
FullPath = "c:\\windows\\system32\\notepad.exe",
LnkResolvedPath = "c:\\programdata\\microsoft\\windows\\start menu\\programs\\accessories\\notepad.lnk",
AppType = 2,
AppType = Win32Program.ApplicationType.Win32Application,
};
private static readonly Win32Program _azureCommandPrompt = new Win32Program
@ -41,7 +42,7 @@ namespace Microsoft.Plugin.Program.UnitTests.Programs
ExecutableName = "cmd.exe",
FullPath = "c:\\windows\\system32\\cmd.exe",
LnkResolvedPath = "c:\\programdata\\microsoft\\windows\\start menu\\programs\\microsoft azure\\microsoft azure sdk for .net\\v2.9\\microsoft azure command prompt - v2.9.lnk",
AppType = 2,
AppType = Win32Program.ApplicationType.Win32Application,
};
private static readonly Win32Program _visualStudioCommandPrompt = new Win32Program
@ -50,7 +51,7 @@ namespace Microsoft.Plugin.Program.UnitTests.Programs
ExecutableName = "cmd.exe",
FullPath = "c:\\windows\\system32\\cmd.exe",
LnkResolvedPath = "c:\\programdata\\microsoft\\windows\\start menu\\programs\\visual studio 2019\\visual studio tools\\vc\\x64 native tools command prompt for vs 2019.lnk",
AppType = 2,
AppType = Win32Program.ApplicationType.Win32Application,
};
private static readonly Win32Program _commandPrompt = new Win32Program
@ -59,7 +60,7 @@ namespace Microsoft.Plugin.Program.UnitTests.Programs
ExecutableName = "cmd.exe",
FullPath = "c:\\windows\\system32\\cmd.exe",
LnkResolvedPath = "c:\\users\\powertoys\\appdata\\roaming\\microsoft\\windows\\start menu\\programs\\system tools\\command prompt.lnk",
AppType = 2,
AppType = Win32Program.ApplicationType.Win32Application,
};
private static readonly Win32Program _fileExplorer = new Win32Program
@ -68,7 +69,7 @@ namespace Microsoft.Plugin.Program.UnitTests.Programs
ExecutableName = "File Explorer.lnk",
FullPath = "c:\\users\\powertoys\\appdata\\roaming\\microsoft\\windows\\start menu\\programs\\system tools\\file explorer.lnk",
LnkResolvedPath = null,
AppType = 2,
AppType = Win32Program.ApplicationType.Win32Application,
};
private static readonly Win32Program _wordpad = new Win32Program
@ -77,7 +78,7 @@ namespace Microsoft.Plugin.Program.UnitTests.Programs
ExecutableName = "wordpad.exe",
FullPath = "c:\\program files\\windows nt\\accessories\\wordpad.exe",
LnkResolvedPath = "c:\\programdata\\microsoft\\windows\\start menu\\programs\\accessories\\wordpad.lnk",
AppType = 2,
AppType = Win32Program.ApplicationType.Win32Application,
};
private static readonly Win32Program _wordpadDuplicate = new Win32Program
@ -86,7 +87,7 @@ namespace Microsoft.Plugin.Program.UnitTests.Programs
ExecutableName = "WORDPAD.EXE",
FullPath = "c:\\program files\\windows nt\\accessories\\wordpad.exe",
LnkResolvedPath = null,
AppType = 2,
AppType = Win32Program.ApplicationType.Win32Application,
};
private static readonly Win32Program _twitterChromePwa = new Win32Program
@ -122,7 +123,7 @@ namespace Microsoft.Plugin.Program.UnitTests.Programs
ExecutableName = "msedge.exe",
FullPath = "c:\\program files (x86)\\microsoft\\edge\\application\\msedge.exe",
LnkResolvedPath = "c:\\programdata\\microsoft\\windows\\start menu\\programs\\microsoft edge.lnk",
AppType = 2,
AppType = Win32Program.ApplicationType.Win32Application,
};
private static readonly Win32Program _chrome = new Win32Program
@ -131,7 +132,7 @@ namespace Microsoft.Plugin.Program.UnitTests.Programs
ExecutableName = "chrome.exe",
FullPath = "c:\\program files (x86)\\google\\chrome\\application\\chrome.exe",
LnkResolvedPath = "c:\\programdata\\microsoft\\windows\\start menu\\programs\\google chrome.lnk",
AppType = 2,
AppType = Win32Program.ApplicationType.Win32Application,
};
private static readonly Win32Program _dummyProxyApp = new Win32Program
@ -140,7 +141,7 @@ namespace Microsoft.Plugin.Program.UnitTests.Programs
ExecutableName = "test_proxy.exe",
FullPath = "c:\\program files (x86)\\microsoft\\edge\\application\\test_proxy.exe",
LnkResolvedPath = "c:\\programdata\\microsoft\\windows\\start menu\\programs\\test proxy.lnk",
AppType = 2,
AppType = Win32Program.ApplicationType.Win32Application,
};
private static readonly Win32Program _cmdRunCommand = new Win32Program
@ -149,7 +150,7 @@ namespace Microsoft.Plugin.Program.UnitTests.Programs
ExecutableName = "cmd.exe",
FullPath = "c:\\windows\\system32\\cmd.exe",
LnkResolvedPath = null,
AppType = 3, // Run command
AppType = Win32Program.ApplicationType.RunCommand, // Run command
};
private static readonly Win32Program _cmderRunCommand = new Win32Program
@ -159,7 +160,7 @@ namespace Microsoft.Plugin.Program.UnitTests.Programs
ExecutableName = "Cmder.exe",
FullPath = "c:\\tools\\cmder\\cmder.exe",
LnkResolvedPath = null,
AppType = 3, // Run command
AppType = Win32Program.ApplicationType.RunCommand, // Run command
};
private static readonly Win32Program _dummyInternetShortcutApp = new Win32Program
@ -169,7 +170,7 @@ namespace Microsoft.Plugin.Program.UnitTests.Programs
FullPath = "steam://rungameid/1258080",
ParentDirectory = "C:\\Users\\temp\\AppData\\Roaming\\Microsoft\\Windows\\Start Menu\\Programs\\Steam",
LnkResolvedPath = null,
AppType = 1,
AppType = Win32Program.ApplicationType.InternetShortcutApplication,
};
private static readonly Win32Program _dummyInternetShortcutAppDuplicate = new Win32Program
@ -179,9 +180,59 @@ namespace Microsoft.Plugin.Program.UnitTests.Programs
FullPath = "steam://rungameid/1258080",
ParentDirectory = "C:\\Users\\temp\\Desktop",
LnkResolvedPath = null,
AppType = 1,
AppType = Win32Program.ApplicationType.InternetShortcutApplication,
};
private static readonly Win32Program _dummyAppRefApp = new Win32Program
{
Name = "Dummy AppRef Application",
ExecutableName = "dummy.appref-ms",
FullPath = "C:\\dummy.appref-ms",
ParentDirectory = "C:\\",
LnkResolvedPath = null,
AppType = Win32Program.ApplicationType.ApprefApplication,
};
private static readonly Win32Program _dummyShortcutApp = new Win32Program
{
Name = "Dummy Shortcut Application",
ExecutableName = "application.lnk",
FullPath = "C:\\application.lnk",
ParentDirectory = "C:\\",
LnkResolvedPath = "C:\\application.lnk",
AppType = Win32Program.ApplicationType.ShortcutApplication,
};
private static readonly Win32Program _dummyFolderApp = new Win32Program
{
Name = "Dummy Folder",
ExecutableName = "application.lnk",
FullPath = "C:\\dummy\\folder",
ParentDirectory = "C:\\dummy\\",
LnkResolvedPath = "C:\\tools\\application.lnk",
AppType = Win32Program.ApplicationType.Folder,
};
private static readonly Win32Program _dummyGenericFileApp = new Win32Program
{
Name = "Dummy Folder",
ExecutableName = "application.lnk",
FullPath = "C:\\dummy\\file.pdf",
ParentDirectory = "C:\\dummy\\",
LnkResolvedPath = "C:\\tools\\application.lnk",
AppType = Win32Program.ApplicationType.GenericFile,
};
private static IDirectoryWrapper GetMockedDirectoryWrapper()
{
var mockDirectory = new Mock<IDirectoryWrapper>();
// Check if the file has no extension. This is not actually true since there can be files without extensions, but this is sufficient for the purpose of a mock function
Func<string, bool> returnValue = arg => string.IsNullOrEmpty(System.IO.Path.GetExtension(arg));
mockDirectory.Setup(m => m.Exists(It.IsAny<string>())).Returns(returnValue);
return mockDirectory.Object;
}
[Test]
public void DedupFunctionWhenCalledMustRemoveDuplicateNotepads()
{
@ -427,6 +478,68 @@ namespace Microsoft.Plugin.Program.UnitTests.Programs
Assert.AreEqual(contextMenuResults[2].Title, Properties.Resources.wox_plugin_program_open_in_console);
}
[Test]
public void AppRefApplicationShouldReturnContextMenuWithOpenInConsoleWhenContextMenusIsCalled()
{
// Arrange
var mock = new Mock<IPublicAPI>();
// Act
List<ContextMenuResult> contextMenuResults = _dummyAppRefApp.ContextMenus(mock.Object);
// Assert
Assert.AreEqual(contextMenuResults.Count, 3);
Assert.AreEqual(contextMenuResults[0].Title, Properties.Resources.wox_plugin_program_run_as_administrator);
Assert.AreEqual(contextMenuResults[1].Title, Properties.Resources.wox_plugin_program_open_containing_folder);
Assert.AreEqual(contextMenuResults[2].Title, Properties.Resources.wox_plugin_program_open_in_console);
}
[Test]
public void ShortcutApplicationShouldReturnContextMenuWithOpenInConsoleWhenContextMenusIsCalled()
{
// Arrange
var mock = new Mock<IPublicAPI>();
// Act
List<ContextMenuResult> contextMenuResults = _dummyShortcutApp.ContextMenus(mock.Object);
// Assert
Assert.AreEqual(contextMenuResults.Count, 3);
Assert.AreEqual(contextMenuResults[0].Title, Properties.Resources.wox_plugin_program_run_as_administrator);
Assert.AreEqual(contextMenuResults[1].Title, Properties.Resources.wox_plugin_program_open_containing_folder);
Assert.AreEqual(contextMenuResults[2].Title, Properties.Resources.wox_plugin_program_open_in_console);
}
[Test]
public void FolderApplicationShouldReturnContextMenuWithOpenInConsoleWhenContextMenusIsCalled()
{
// Arrange
var mock = new Mock<IPublicAPI>();
// Act
List<ContextMenuResult> contextMenuResults = _dummyFolderApp.ContextMenus(mock.Object);
// Assert
Assert.AreEqual(contextMenuResults.Count, 2);
Assert.AreEqual(contextMenuResults[0].Title, Properties.Resources.wox_plugin_program_open_containing_folder);
Assert.AreEqual(contextMenuResults[1].Title, Properties.Resources.wox_plugin_program_open_in_console);
}
[Test]
public void GenericFileApplicationShouldReturnContextMenuWithOpenInConsoleWhenContextMenusIsCalled()
{
// Arrange
var mock = new Mock<IPublicAPI>();
// Act
List<ContextMenuResult> contextMenuResults = _dummyGenericFileApp.ContextMenus(mock.Object);
// Assert
Assert.AreEqual(contextMenuResults.Count, 2);
Assert.AreEqual(contextMenuResults[0].Title, Properties.Resources.wox_plugin_program_open_containing_folder);
Assert.AreEqual(contextMenuResults[1].Title, Properties.Resources.wox_plugin_program_open_in_console);
}
[Test]
public void Win32AppsShouldSetNameAsTitleWhileCreatingResult()
{
@ -440,5 +553,21 @@ namespace Microsoft.Plugin.Program.UnitTests.Programs
Assert.IsTrue(result.Title.Equals(_cmderRunCommand.Name, StringComparison.Ordinal));
Assert.IsFalse(result.Title.Equals(_cmderRunCommand.Description, StringComparison.Ordinal));
}
[TestCase("C:\\Program Files\\dummy.exe", ExpectedResult = Win32Program.ApplicationType.Win32Application)]
[TestCase("C:\\Program Files\\dummy.msc", ExpectedResult = Win32Program.ApplicationType.Win32Application)]
[TestCase("C:\\Program Files\\dummy.lnk", ExpectedResult = Win32Program.ApplicationType.ShortcutApplication)]
[TestCase("C:\\Program Files\\dummy.appref-ms", ExpectedResult = Win32Program.ApplicationType.ApprefApplication)]
[TestCase("C:\\Program Files\\dummy.url", ExpectedResult = Win32Program.ApplicationType.InternetShortcutApplication)]
[TestCase("C:\\Program Files\\dummy", ExpectedResult = Win32Program.ApplicationType.Folder)]
[TestCase("C:\\Program Files\\dummy.txt", ExpectedResult = Win32Program.ApplicationType.GenericFile)]
public Win32Program.ApplicationType GetAppTypeFromPathShouldReturnCorrectAppTypeWhenAppPathIsPassedAsArgument(string path)
{
// Directory.Exists must be mocked
Win32Program.DirectoryWrapper = GetMockedDirectoryWrapper();
// Act
return Win32Program.GetAppTypeFromPath(path);
}
}
}

View File

@ -84,7 +84,7 @@ namespace Microsoft.Plugin.Program.UnitTests.Storage
// Assert
Assert.AreEqual(win32ProgramRepository.Count(), 1);
Assert.AreEqual(win32ProgramRepository.ElementAt(0).AppType, 2);
Assert.AreEqual(win32ProgramRepository.ElementAt(0).AppType, Win32Program.ApplicationType.ApprefApplication);
}
[TestCase("directory", "path.appref-ms")]
@ -145,7 +145,7 @@ namespace Microsoft.Plugin.Program.UnitTests.Storage
// Assert
Assert.AreEqual(win32ProgramRepository.Count(), 1);
Assert.AreEqual(win32ProgramRepository.ElementAt(0).AppType, 2);
Assert.AreEqual(win32ProgramRepository.ElementAt(0).AppType, Win32Program.ApplicationType.Win32Application);
}
[TestCase("directory", "path.exe")]
@ -216,7 +216,7 @@ namespace Microsoft.Plugin.Program.UnitTests.Storage
// Assert
Assert.AreEqual(win32ProgramRepository.Count(), 1);
Assert.AreEqual(win32ProgramRepository.ElementAt(0).AppType, 1); // Internet Shortcut Application
Assert.AreEqual(win32ProgramRepository.ElementAt(0).AppType, Win32Program.ApplicationType.InternetShortcutApplication); // Internet Shortcut Application
}
[TestCase("path.url")]
@ -336,7 +336,7 @@ namespace Microsoft.Plugin.Program.UnitTests.Storage
// Assert
Assert.AreEqual(win32ProgramRepository.Count(), 1);
Assert.AreEqual(win32ProgramRepository.ElementAt(0).AppType, 2);
Assert.AreEqual(win32ProgramRepository.ElementAt(0).AppType, Win32Program.ApplicationType.Win32Application);
}
[TestCase("directory", "path.lnk")]

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();
}

View File

@ -78,6 +78,24 @@ namespace Microsoft.Plugin.Program.Properties {
}
}
/// <summary>
/// Looks up a localized string similar to Folder.
/// </summary>
public static string powertoys_run_plugin_program_folder_type {
get {
return ResourceManager.GetString("powertoys_run_plugin_program_folder_type", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to File.
/// </summary>
public static string powertoys_run_plugin_program_generic_file_type {
get {
return ResourceManager.GetString("powertoys_run_plugin_program_generic_file_type", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Internet shortcut application.
/// </summary>

View File

@ -153,6 +153,12 @@
<data name="powertoys_run_plugin_program_file_path" xml:space="preserve">
<value>Path</value>
</data>
<data name="powertoys_run_plugin_program_folder_type" xml:space="preserve">
<value>Folder</value>
</data>
<data name="powertoys_run_plugin_program_generic_file_type" xml:space="preserve">
<value>File</value>
</data>
<data name="powertoys_run_plugin_program_start_failed" xml:space="preserve">
<value>Unable to start</value>
</data>

View File

@ -69,6 +69,7 @@ namespace Microsoft.Plugin.Program.Storage
string newPath = e.FullPath;
string extension = Path.GetExtension(newPath);
Win32Program.ApplicationType appType = Win32Program.GetAppTypeFromPath(newPath);
Programs.Win32Program newApp = Programs.Win32Program.GetAppFromPath(newPath);
Programs.Win32Program oldApp = null;
@ -78,11 +79,11 @@ namespace Microsoft.Plugin.Program.Storage
// This situation is not encountered for other application types because the fullPath is the path itself, instead of being computed by using the path to the app.
try
{
if (extension.Equals(LnkExtension, StringComparison.OrdinalIgnoreCase))
if (appType == Win32Program.ApplicationType.ShortcutApplication)
{
oldApp = new Win32Program() { Name = Path.GetFileNameWithoutExtension(e.OldName), ExecutableName = newApp.ExecutableName, FullPath = newApp.FullPath };
}
else if (extension.Equals(UrlExtension, StringComparison.OrdinalIgnoreCase))
else if (appType == Win32Program.ApplicationType.InternetShortcutApplication)
{
oldApp = new Win32Program() { Name = Path.GetFileNameWithoutExtension(e.OldName), ExecutableName = Path.GetFileName(e.OldName), FullPath = newApp.FullPath };
}

View File

@ -0,0 +1,18 @@
// Copyright (c) Microsoft Corporation
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
namespace Wox.Infrastructure.FileSystemHelper
{
public class DirectoryWrapper : IDirectoryWrapper
{
public DirectoryWrapper()
{
}
public bool Exists(string path)
{
return System.IO.Directory.Exists(path);
}
}
}

View File

@ -0,0 +1,11 @@
// Copyright (c) Microsoft Corporation
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
namespace Wox.Infrastructure.FileSystemHelper
{
public interface IDirectoryWrapper
{
bool Exists(string path);
}
}