mirror of
https://github.com/microsoft/PowerToys.git
synced 2025-12-29 16:36:40 +01:00
Compare commits
4 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2ba99d14e1 | ||
|
|
bbbbf0954d | ||
|
|
f81ccdda3d | ||
|
|
ef7285fb9a |
@@ -41,6 +41,11 @@ build:
|
||||
name: 'Build Power Toys'
|
||||
command: '.pipelines\build.cmd'
|
||||
artifacts:
|
||||
- to: 'Symbols'
|
||||
include:
|
||||
- 'x64/**/*.pdb'
|
||||
exclude:
|
||||
- 'x64/Release/obj/**/*.pdb'
|
||||
- from: 'x64/Release'
|
||||
to: 'Build_Output'
|
||||
include:
|
||||
@@ -127,20 +132,6 @@ build:
|
||||
- 'PowerToysSetup-*.msi'
|
||||
signing_options:
|
||||
sign_inline: true # This does signing a soon as this command completes
|
||||
# - !!buildcommand
|
||||
# name: 'Archive symbols to Symbol Server'
|
||||
# artifacts:
|
||||
# - to: 'x64 Symbols'
|
||||
# include:
|
||||
# - 'x64/Release/action_runner.pdb'
|
||||
# - 'x64/Release/Notifications.pdb'
|
||||
# - 'x64/Release/PowerRenameUWPUI.pdb'
|
||||
# - 'x64/Release/PowerToys.pdb'
|
||||
# - 'x64/Release/PowerToysSettings.pdb'
|
||||
# - 'x64/Release/modules/fancyzones.pdb'
|
||||
# - 'x64/Release/modules/FancyZonesEditor.pdb'
|
||||
# - 'x64/Release/modules/PowerRenameExt.pdb'
|
||||
# - 'x64/Release/modules/shortcut_guide.pdb'
|
||||
|
||||
package:
|
||||
commands:
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup>
|
||||
<Version>0.18.1</Version>
|
||||
<Version>0.18.2</Version>
|
||||
<DefineConstants>Version=$(Version);</DefineConstants>
|
||||
</PropertyGroup>
|
||||
</Project>
|
||||
@@ -186,26 +186,23 @@ int WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int)
|
||||
}
|
||||
std::wstring_view action{ args[1] };
|
||||
|
||||
|
||||
if (action == L"-start_PowerLauncher")
|
||||
{
|
||||
if (is_process_elevated(false) == true)
|
||||
{
|
||||
drop_elevated_privileges();
|
||||
}
|
||||
|
||||
HANDLE hMapFile = OpenFileMappingW(FILE_MAP_WRITE, FALSE, POWER_LAUNCHER_PID_SHARED_FILE);
|
||||
PDWORD pidBuffer = reinterpret_cast<PDWORD>(MapViewOfFile(hMapFile, FILE_MAP_ALL_ACCESS, 0, 0, sizeof(DWORD)));
|
||||
if (pidBuffer)
|
||||
if (hMapFile)
|
||||
{
|
||||
*pidBuffer = 0;
|
||||
run_non_elevated(L"modules\\launcher\\PowerLauncher.exe", L"", pidBuffer);
|
||||
FlushViewOfFile(pidBuffer, sizeof(DWORD));
|
||||
UnmapViewOfFile(pidBuffer);
|
||||
}
|
||||
PDWORD pidBuffer = reinterpret_cast<PDWORD>(MapViewOfFile(hMapFile, FILE_MAP_ALL_ACCESS, 0, 0, sizeof(DWORD)));
|
||||
if (pidBuffer)
|
||||
{
|
||||
*pidBuffer = 0;
|
||||
run_same_elevation(L"modules\\launcher\\PowerLauncher.exe", L"", pidBuffer);
|
||||
FlushViewOfFile(pidBuffer, sizeof(DWORD));
|
||||
UnmapViewOfFile(pidBuffer);
|
||||
}
|
||||
|
||||
FlushFileBuffers(hMapFile);
|
||||
CloseHandle(hMapFile);
|
||||
FlushFileBuffers(hMapFile);
|
||||
CloseHandle(hMapFile);
|
||||
}
|
||||
}
|
||||
else if (action == L"-install_dotnet")
|
||||
{
|
||||
|
||||
@@ -510,8 +510,8 @@ bool run_non_elevated(const std::wstring& file, const std::wstring& params, DWOR
|
||||
siex.lpAttributeList = pptal;
|
||||
siex.StartupInfo.cb = sizeof(siex);
|
||||
|
||||
PROCESS_INFORMATION process_info = { 0 };
|
||||
auto succedded = CreateProcessW(file.c_str(),
|
||||
PROCESS_INFORMATION pi = { 0 };
|
||||
auto succeeded = CreateProcessW(file.c_str(),
|
||||
const_cast<LPWSTR>(executable_args.c_str()),
|
||||
nullptr,
|
||||
nullptr,
|
||||
@@ -520,34 +520,38 @@ bool run_non_elevated(const std::wstring& file, const std::wstring& params, DWOR
|
||||
nullptr,
|
||||
nullptr,
|
||||
&siex.StartupInfo,
|
||||
&process_info);
|
||||
|
||||
if (process_info.hProcess)
|
||||
&pi);
|
||||
if (succeeded)
|
||||
{
|
||||
if (returnPid)
|
||||
if (pi.hProcess)
|
||||
{
|
||||
*returnPid = GetProcessId(process_info.hProcess);
|
||||
}
|
||||
if (returnPid)
|
||||
{
|
||||
*returnPid = GetProcessId(pi.hProcess);
|
||||
}
|
||||
|
||||
CloseHandle(process_info.hProcess);
|
||||
CloseHandle(pi.hProcess);
|
||||
}
|
||||
if (pi.hThread)
|
||||
{
|
||||
CloseHandle(pi.hThread);
|
||||
}
|
||||
}
|
||||
if (process_info.hThread)
|
||||
{
|
||||
CloseHandle(process_info.hThread);
|
||||
}
|
||||
return succedded;
|
||||
|
||||
return succeeded;
|
||||
}
|
||||
|
||||
bool run_same_elevation(const std::wstring& file, const std::wstring& params)
|
||||
bool run_same_elevation(const std::wstring& file, const std::wstring& params, DWORD* returnPid)
|
||||
{
|
||||
auto executable_args = L"\"" + file + L"\"";
|
||||
if (!params.empty())
|
||||
{
|
||||
executable_args += L" " + params;
|
||||
}
|
||||
|
||||
STARTUPINFO si = { 0 };
|
||||
PROCESS_INFORMATION pi = { 0 };
|
||||
auto succedded = CreateProcessW(file.c_str(),
|
||||
auto succeeded = CreateProcessW(file.c_str(),
|
||||
const_cast<LPWSTR>(executable_args.c_str()),
|
||||
nullptr,
|
||||
nullptr,
|
||||
@@ -557,15 +561,26 @@ bool run_same_elevation(const std::wstring& file, const std::wstring& params)
|
||||
nullptr,
|
||||
&si,
|
||||
&pi);
|
||||
if (pi.hProcess)
|
||||
|
||||
if (succeeded)
|
||||
{
|
||||
CloseHandle(pi.hProcess);
|
||||
if (pi.hProcess)
|
||||
{
|
||||
if (returnPid)
|
||||
{
|
||||
*returnPid = GetProcessId(pi.hProcess);
|
||||
}
|
||||
|
||||
CloseHandle(pi.hProcess);
|
||||
}
|
||||
|
||||
if (pi.hThread)
|
||||
{
|
||||
CloseHandle(pi.hThread);
|
||||
}
|
||||
}
|
||||
if (pi.hThread)
|
||||
{
|
||||
CloseHandle(pi.hThread);
|
||||
}
|
||||
return succedded;
|
||||
|
||||
return succeeded;
|
||||
}
|
||||
|
||||
std::wstring get_process_path(HWND window) noexcept
|
||||
|
||||
@@ -72,8 +72,8 @@ bool run_elevated(const std::wstring& file, const std::wstring& params);
|
||||
// Run command as non-elevated user, returns true if succeeded, puts the process id into returnPid if returnPid != NULL
|
||||
bool run_non_elevated(const std::wstring& file, const std::wstring& params, DWORD* returnPid);
|
||||
|
||||
// Run command with the same elevation, returns true if succedded
|
||||
bool run_same_elevation(const std::wstring& file, const std::wstring& params);
|
||||
// Run command with the same elevation, returns true if succeeded
|
||||
bool run_same_elevation(const std::wstring& file, const std::wstring& params, DWORD* returnPid);
|
||||
|
||||
// Returns true if the current process is running from administrator account
|
||||
bool check_user_is_admin();
|
||||
@@ -137,4 +137,4 @@ struct overloaded : Ts...
|
||||
template<class... Ts>
|
||||
overloaded(Ts...)->overloaded<Ts...>;
|
||||
|
||||
#define POWER_LAUNCHER_PID_SHARED_FILE L"Global\\3cbfbad4-199b-4e2c-9825-942d5d3d3c74"
|
||||
#define POWER_LAUNCHER_PID_SHARED_FILE L"Local\\3cbfbad4-199b-4e2c-9825-942d5d3d3c74"
|
||||
|
||||
@@ -14,7 +14,7 @@ namespace Microsoft.PowerLauncher.Telemetry
|
||||
/// <summary>
|
||||
/// Gets The version string. TODO: This should be replaced by a P/Invoke call to get_product_version
|
||||
/// </summary>
|
||||
public string Version => "v0.18.1";
|
||||
public string Version => "v0.18.2";
|
||||
|
||||
public double BootTimeMs { get; set; }
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
<RepositoryUrl>https://github.com/microsoft/PowerToys</RepositoryUrl>
|
||||
<RepositoryType>Github</RepositoryType>
|
||||
<PackageTags>PowerToys</PackageTags>
|
||||
<Version>0.15.2.0</Version>
|
||||
<Version>0.18.2.0</Version>
|
||||
<Platforms>x64</Platforms>
|
||||
<ApplicationIcon>icon.ico</ApplicationIcon>
|
||||
<Win32Resource />
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
<Identity
|
||||
Name="f4f787a5-f0ae-47a9-be89-5408b1dd2b47"
|
||||
Publisher="CN=lamotile"
|
||||
Version="0.15.2.0" />
|
||||
Version="0.18.2.0" />
|
||||
|
||||
<mp:PhoneIdentity PhoneProductId="f4f787a5-f0ae-47a9-be89-5408b1dd2b47" PhonePublisherId="00000000-0000-0000-0000-000000000000"/>
|
||||
|
||||
|
||||
@@ -132,7 +132,7 @@ public:
|
||||
// Enable the powertoy
|
||||
virtual void enable()
|
||||
{
|
||||
if (is_process_elevated(false) == false)
|
||||
if (!is_process_elevated(false))
|
||||
{
|
||||
SHELLEXECUTEINFOW sei{ sizeof(sei) };
|
||||
sei.fMask = { SEE_MASK_NOCLOSEPROCESS | SEE_MASK_FLAG_NO_UI };
|
||||
@@ -146,32 +146,34 @@ public:
|
||||
{
|
||||
std::wstring action_runner_path = get_module_folderpath();
|
||||
action_runner_path += L"\\action_runner.exe";
|
||||
SHELLEXECUTEINFOW sei{ sizeof(sei) };
|
||||
sei.fMask = { SEE_MASK_NOCLOSEPROCESS | SEE_MASK_FLAG_NO_UI | SEE_MASK_NOASYNC };
|
||||
sei.lpFile = action_runner_path.c_str();
|
||||
sei.nShow = SW_SHOWNORMAL;
|
||||
sei.lpParameters = L"-start_PowerLauncher";
|
||||
|
||||
|
||||
// Set up the shared file from which to retrieve the PID of PowerLauncher
|
||||
HANDLE hMapFile = CreateFileMappingW(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, sizeof(DWORD), POWER_LAUNCHER_PID_SHARED_FILE);
|
||||
PDWORD pidBuffer = reinterpret_cast<PDWORD>(MapViewOfFile(hMapFile, FILE_MAP_ALL_ACCESS, 0, 0, sizeof(DWORD)));
|
||||
*pidBuffer = 0;
|
||||
m_hProcess = NULL;
|
||||
ShellExecuteExW(&sei);
|
||||
|
||||
const int maxRetries = 20;
|
||||
for (int retry = 0; retry < maxRetries; ++retry)
|
||||
if (hMapFile)
|
||||
{
|
||||
Sleep(50);
|
||||
DWORD pid = *pidBuffer;
|
||||
if (pid)
|
||||
PDWORD pidBuffer = reinterpret_cast<PDWORD>(MapViewOfFile(hMapFile, FILE_MAP_ALL_ACCESS, 0, 0, sizeof(DWORD)));
|
||||
if (pidBuffer)
|
||||
{
|
||||
m_hProcess = OpenProcess(PROCESS_TERMINATE, FALSE, pid);
|
||||
break;
|
||||
}
|
||||
}
|
||||
*pidBuffer = 0;
|
||||
m_hProcess = NULL;
|
||||
|
||||
CloseHandle(hMapFile);
|
||||
if (run_non_elevated(action_runner_path, L"-start_PowerLauncher", nullptr))
|
||||
{
|
||||
const int maxRetries = 20;
|
||||
for (int retry = 0; retry < maxRetries; ++retry)
|
||||
{
|
||||
Sleep(50);
|
||||
DWORD pid = *pidBuffer;
|
||||
if (pid)
|
||||
{
|
||||
m_hProcess = OpenProcess(PROCESS_TERMINATE, FALSE, pid);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
CloseHandle(hMapFile);
|
||||
}
|
||||
}
|
||||
|
||||
m_enabled = true;
|
||||
|
||||
@@ -449,6 +449,10 @@ namespace Microsoft.Plugin.Program.Programs
|
||||
{
|
||||
parsed = prefix + "//" + key;
|
||||
}
|
||||
else if (key.Contains("resources", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
parsed = prefix + key;
|
||||
}
|
||||
else
|
||||
{
|
||||
parsed = prefix + "///resources/" + key;
|
||||
|
||||
@@ -443,6 +443,46 @@ namespace Microsoft.Plugin.Program.Programs
|
||||
return entry;
|
||||
}
|
||||
|
||||
public class removeDuplicatesComparer : IEqualityComparer<Win32>
|
||||
{
|
||||
public bool Equals(Win32 app1, Win32 app2)
|
||||
{
|
||||
|
||||
if(!string.IsNullOrEmpty(app1.Name) && !string.IsNullOrEmpty(app2.Name)
|
||||
&& !string.IsNullOrEmpty(app1.ExecutableName) && !string.IsNullOrEmpty(app2.ExecutableName)
|
||||
&& !string.IsNullOrEmpty(app1.FullPath) && !string.IsNullOrEmpty(app2.FullPath))
|
||||
{
|
||||
return app1.Name.Equals(app2.Name, StringComparison.OrdinalIgnoreCase)
|
||||
&& app1.ExecutableName.Equals(app2.ExecutableName, StringComparison.OrdinalIgnoreCase)
|
||||
&& app1.FullPath.Equals(app2.FullPath, StringComparison.OrdinalIgnoreCase);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// Ref : https://stackoverflow.com/questions/2730865/how-do-i-calculate-a-good-hash-code-for-a-list-of-strings
|
||||
public int GetHashCode(Win32 obj)
|
||||
{
|
||||
int namePrime = 13;
|
||||
int executablePrime = 17;
|
||||
int fullPathPrime = 31;
|
||||
|
||||
int result = 1;
|
||||
result = result * namePrime + obj.Name.GetHashCode();
|
||||
result = result * executablePrime + obj.ExecutableName.GetHashCode();
|
||||
result = result * fullPathPrime + obj.FullPath.GetHashCode();
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
// Deduplication code
|
||||
public static Func<ParallelQuery<Win32>, Win32[]> DeduplicatePrograms = (programs) =>
|
||||
{
|
||||
var uniqueExePrograms = programs.Where(x => !string.IsNullOrEmpty(x.LnkResolvedPath) || Extension(x.FullPath) != ExeExtension);
|
||||
var uniquePrograms = uniqueExePrograms.Distinct(new removeDuplicatesComparer());
|
||||
return uniquePrograms.ToArray();
|
||||
};
|
||||
|
||||
public static Win32[] All(Settings settings)
|
||||
{
|
||||
try
|
||||
@@ -464,15 +504,7 @@ namespace Microsoft.Plugin.Program.Programs
|
||||
programs = programs.Concat(startMenu);
|
||||
}
|
||||
|
||||
var programsWithoutLnk = programs.Where(x => string.IsNullOrEmpty(x.LnkResolvedPath));
|
||||
var programsAsList = programs.ToList();
|
||||
|
||||
foreach(var app in programsWithoutLnk)
|
||||
{
|
||||
programsAsList.RemoveAll(x => (x.FullPath == app.FullPath) && string.IsNullOrEmpty(x.LnkResolvedPath));
|
||||
}
|
||||
|
||||
return programsAsList.ToArray();
|
||||
return DeduplicatePrograms(programs);
|
||||
}
|
||||
#if DEBUG //This is to make developer aware of any unhandled exception and add in handling.
|
||||
catch (Exception e)
|
||||
|
||||
@@ -10,7 +10,7 @@ namespace Microsoft.PowerLauncher.Telemetry
|
||||
/// <summary>
|
||||
/// TODO: This should be replaced by a P/Invoke call to get_product_version
|
||||
/// </summary>
|
||||
public string Version => "v0.18.1";
|
||||
public string Version => "v0.18.2";
|
||||
|
||||
public double BootTimeMs { get; set; }
|
||||
|
||||
|
||||
@@ -83,9 +83,18 @@ namespace Wox.Infrastructure
|
||||
bool allSubstringsContainedInCompareString = true;
|
||||
|
||||
var indexList = new List<int>();
|
||||
List<int> spaceIndices = new List<int>();
|
||||
|
||||
for (var compareStringIndex = 0; compareStringIndex < fullStringToCompareWithoutCase.Length; compareStringIndex++)
|
||||
{
|
||||
|
||||
// To maintain a list of indices which correspond to spaces in the string to compare
|
||||
// To populate the list only for the first query substring
|
||||
if (fullStringToCompareWithoutCase[compareStringIndex].Equals(' ') && currentQuerySubstringIndex == 0)
|
||||
{
|
||||
spaceIndices.Add(compareStringIndex);
|
||||
}
|
||||
|
||||
if (fullStringToCompareWithoutCase[compareStringIndex] != currentQuerySubstring[currentQuerySubstringCharacterIndex])
|
||||
{
|
||||
matchFoundInPreviousLoop = false;
|
||||
@@ -147,7 +156,8 @@ namespace Wox.Infrastructure
|
||||
// proceed to calculate score if every char or substring without whitespaces matched
|
||||
if (allQuerySubstringsMatched)
|
||||
{
|
||||
var score = CalculateSearchScore(query, stringToCompare, firstMatchIndex, lastMatchIndex - firstMatchIndex, allSubstringsContainedInCompareString);
|
||||
var nearestSpaceIndex = CalculateClosestSpaceIndex(spaceIndices, firstMatchIndex);
|
||||
var score = CalculateSearchScore(query, stringToCompare, firstMatchIndex - nearestSpaceIndex - 1, lastMatchIndex - firstMatchIndex, allSubstringsContainedInCompareString);
|
||||
|
||||
return new MatchResult(true, UserSettingSearchPrecision, indexList, score);
|
||||
}
|
||||
@@ -155,6 +165,21 @@ namespace Wox.Infrastructure
|
||||
return new MatchResult (false, UserSettingSearchPrecision);
|
||||
}
|
||||
|
||||
// To get the index of the closest space which preceeds the first matching index
|
||||
private int CalculateClosestSpaceIndex(List<int> spaceIndices, int firstMatchIndex)
|
||||
{
|
||||
if(spaceIndices.Count == 0)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
int? ind = spaceIndices.OrderBy(item => (firstMatchIndex - item)).Where(item => firstMatchIndex > item).FirstOrDefault();
|
||||
int closestSpaceIndex = ind ?? -1;
|
||||
return closestSpaceIndex;
|
||||
}
|
||||
}
|
||||
|
||||
private static bool AllPreviousCharsMatched(int startIndexToVerify, int currentQuerySubstringCharacterIndex,
|
||||
string fullStringToCompareWithoutCase, string currentQuerySubstring)
|
||||
{
|
||||
|
||||
@@ -187,8 +187,6 @@ namespace Wox.Test
|
||||
[TestCase("sql manag", MicrosoftSqlServerManagementStudio, StringMatcher.SearchPrecisionScore.Regular, true)]
|
||||
[TestCase("sql", MicrosoftSqlServerManagementStudio, StringMatcher.SearchPrecisionScore.Regular, true)]
|
||||
[TestCase("sql serv", MicrosoftSqlServerManagementStudio, StringMatcher.SearchPrecisionScore.Regular, true)]
|
||||
[TestCase("sqlserv", MicrosoftSqlServerManagementStudio, StringMatcher.SearchPrecisionScore.Regular, false)]
|
||||
[TestCase("sql servman", MicrosoftSqlServerManagementStudio, StringMatcher.SearchPrecisionScore.Regular, false)]
|
||||
[TestCase("sql serv man", MicrosoftSqlServerManagementStudio, StringMatcher.SearchPrecisionScore.Regular, true)]
|
||||
[TestCase("sql studio", MicrosoftSqlServerManagementStudio, StringMatcher.SearchPrecisionScore.Regular, true)]
|
||||
[TestCase("mic", MicrosoftSqlServerManagementStudio, StringMatcher.SearchPrecisionScore.Regular, true)]
|
||||
@@ -224,5 +222,20 @@ namespace Wox.Test
|
||||
$"Raw Score: {matchResult.RawScore}{Environment.NewLine}" +
|
||||
$"Precision Score: {(int)expectedPrecisionScore}");
|
||||
}
|
||||
|
||||
[TestCase("Windows Terminal", "Windows_Terminal", "term")]
|
||||
[TestCase("Windows Terminal", "WindowsTerminal", "term")]
|
||||
public void FuzzyMatchingScore_ShouldBeHigher_WhenPreceedingCharacterIsSpace(string firstCompareStr, string secondCompareStr, string query)
|
||||
{
|
||||
// Arrange
|
||||
var matcher = new StringMatcher();
|
||||
|
||||
// Act
|
||||
var firstScore = matcher.FuzzyMatch(query, firstCompareStr).Score;
|
||||
var secondScore = matcher.FuzzyMatch(query, secondCompareStr).Score;
|
||||
|
||||
// Assert
|
||||
Assert.IsTrue(firstScore > secondScore);
|
||||
}
|
||||
}
|
||||
}
|
||||
143
src/modules/launcher/Wox.Test/Plugins/ProgramPluginTest.cs
Normal file
143
src/modules/launcher/Wox.Test/Plugins/ProgramPluginTest.cs
Normal file
@@ -0,0 +1,143 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using NUnit.Framework;
|
||||
using Wox.Infrastructure;
|
||||
using Wox.Plugin;
|
||||
using Microsoft.Plugin.Program.Programs;
|
||||
using Moq;
|
||||
using System.IO;
|
||||
|
||||
namespace Wox.Test.Plugins
|
||||
{
|
||||
[TestFixture]
|
||||
public class ProgramPluginTest
|
||||
{
|
||||
Win32 notepad_appdata = new Win32
|
||||
{
|
||||
Name = "Notepad",
|
||||
ExecutableName = "notepad.exe",
|
||||
FullPath = "c:\\windows\\system32\\notepad.exe",
|
||||
LnkResolvedPath = "c:\\users\\powertoys\\appdata\\roaming\\microsoft\\windows\\start menu\\programs\\accessories\\notepad.lnk"
|
||||
};
|
||||
|
||||
Win32 notepad_users = new Win32
|
||||
{
|
||||
Name = "Notepad",
|
||||
ExecutableName = "notepad.exe",
|
||||
FullPath = "c:\\windows\\system32\\notepad.exe",
|
||||
LnkResolvedPath = "c:\\programdata\\microsoft\\windows\\start menu\\programs\\accessories\\notepad.lnk"
|
||||
};
|
||||
|
||||
Win32 azure_command_prompt = new Win32
|
||||
{
|
||||
Name = "Microsoft Azure Command Prompt - v2.9",
|
||||
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"
|
||||
};
|
||||
|
||||
Win32 visual_studio_command_prompt = new Win32
|
||||
{
|
||||
Name = "x64 Native Tools Command Prompt for VS 2019",
|
||||
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"
|
||||
};
|
||||
|
||||
Win32 command_prompt = new Win32
|
||||
{
|
||||
Name = "Command Prompt",
|
||||
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"
|
||||
};
|
||||
|
||||
Win32 file_explorer = new Win32
|
||||
{
|
||||
Name = "File Explorer",
|
||||
ExecutableName = "File Explorer.lnk",
|
||||
FullPath = "c:\\users\\powertoys\\appdata\\roaming\\microsoft\\windows\\start menu\\programs\\system tools\\file explorer.lnk",
|
||||
LnkResolvedPath = null
|
||||
};
|
||||
|
||||
Win32 wordpad = new Win32
|
||||
{
|
||||
Name = "Wordpad",
|
||||
ExecutableName = "wordpad.exe",
|
||||
FullPath = "c:\\program files\\windows nt\\accessories\\wordpad.exe",
|
||||
LnkResolvedPath = "c:\\programdata\\microsoft\\windows\\start menu\\programs\\accessories\\wordpad.lnk"
|
||||
};
|
||||
|
||||
Win32 wordpad_duplicate = new Win32
|
||||
{
|
||||
Name = "WORDPAD",
|
||||
ExecutableName = "WORDPAD.EXE",
|
||||
FullPath = "c:\\program files\\windows nt\\accessories\\wordpad.exe",
|
||||
LnkResolvedPath = null
|
||||
};
|
||||
|
||||
|
||||
[Test]
|
||||
public void DedupFunction_whenCalled_mustRemoveDuplicateNotepads()
|
||||
{
|
||||
// Arrange
|
||||
List<Win32> prgms = new List<Win32>();
|
||||
prgms.Add(notepad_appdata);
|
||||
prgms.Add(notepad_users);
|
||||
|
||||
// Act
|
||||
Win32[] apps = Win32.DeduplicatePrograms(prgms.AsParallel());
|
||||
|
||||
// Assert
|
||||
Assert.AreEqual(apps.Length, 1);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void DedupFunction_whenCalled_mustNotRemovelnkWhichdoesNotHaveExe()
|
||||
{
|
||||
// Arrange
|
||||
List<Win32> prgms = new List<Win32>();
|
||||
prgms.Add(file_explorer);
|
||||
|
||||
// Act
|
||||
Win32[] apps = Win32.DeduplicatePrograms(prgms.AsParallel());
|
||||
|
||||
// Assert
|
||||
Assert.AreEqual(apps.Length, 1);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void DedupFunction_mustRemoveDuplicates_forExeExtensionsWithoutLnkResolvedPath()
|
||||
{
|
||||
// Arrange
|
||||
List<Win32> prgms = new List<Win32>();
|
||||
prgms.Add(wordpad);
|
||||
prgms.Add(wordpad_duplicate);
|
||||
|
||||
// Act
|
||||
Win32[] apps = Win32.DeduplicatePrograms(prgms.AsParallel());
|
||||
|
||||
// Assert
|
||||
Assert.AreEqual(apps.Length, 1);
|
||||
Assert.IsTrue(!string.IsNullOrEmpty(apps[0].LnkResolvedPath));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void DedupFunction_mustNotRemovePrograms_withSameExeNameAndFullPath()
|
||||
{
|
||||
// Arrange
|
||||
List<Win32> prgms = new List<Win32>();
|
||||
prgms.Add(azure_command_prompt);
|
||||
prgms.Add(visual_studio_command_prompt);
|
||||
prgms.Add(command_prompt);
|
||||
|
||||
// Act
|
||||
Win32[] apps = Win32.DeduplicatePrograms(prgms.AsParallel());
|
||||
|
||||
// Assert
|
||||
Assert.AreEqual(apps.Length, 3);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -40,6 +40,7 @@
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Plugins\Microsoft.Plugin.Indexer\Microsoft.Plugin.Indexer.csproj" />
|
||||
<ProjectReference Include="..\Plugins\Microsoft.Plugin.Program\Microsoft.Plugin.Program.csproj" />
|
||||
<ProjectReference Include="..\Wox.Core\Wox.Core.csproj" />
|
||||
<ProjectReference Include="..\Wox.Infrastructure\Wox.Infrastructure.csproj" />
|
||||
<ProjectReference Include="..\Wox.Plugin\Wox.Plugin.csproj" />
|
||||
|
||||
@@ -17,7 +17,7 @@ namespace MarkdownPreviewHandler.Telemetry.Events
|
||||
/// <summary>
|
||||
/// Gets The version string. TODO: This should be replaced by a P/Invoke call to get_product_version.
|
||||
/// </summary>
|
||||
public string Version => "v0.18.1";
|
||||
public string Version => "v0.18.2";
|
||||
|
||||
/// <inheritdoc/>
|
||||
public PartA_PrivTags PartA_PrivTags => PartA_PrivTags.ProductAndServiceUsage;
|
||||
|
||||
@@ -17,7 +17,7 @@ namespace SvgPreviewHandler.Telemetry.Events
|
||||
/// <summary>
|
||||
/// Gets The version string. TODO: This should be replaced by a P/Invoke call to get_product_version.
|
||||
/// </summary>
|
||||
public string Version => "v0.18.1";
|
||||
public string Version => "v0.18.2";
|
||||
|
||||
/// <inheritdoc/>
|
||||
public PartA_PrivTags PartA_PrivTags => PartA_PrivTags.ProductAndServiceUsage;
|
||||
|
||||
@@ -47,5 +47,5 @@ bool restart_same_elevation()
|
||||
constexpr DWORD exe_path_size = 0xFFFF;
|
||||
auto exe_path = std::make_unique<wchar_t[]>(exe_path_size);
|
||||
GetModuleFileNameW(nullptr, exe_path.get(), exe_path_size);
|
||||
return run_same_elevation(exe_path.get(), L"--dont-elevate");
|
||||
return run_same_elevation(exe_path.get(), L"--dont-elevate", nullptr);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user