diff --git a/PowerToys.sln b/PowerToys.sln
index 1ba2940ec1..4af72870f9 100644
--- a/PowerToys.sln
+++ b/PowerToys.sln
@@ -638,8 +638,6 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.CmdPal.UI.ViewMod
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.CmdPal.Ext.ClipboardHistory", "src\modules\cmdpal\ext\Microsoft.CmdPal.Ext.ClipboardHistory\Microsoft.CmdPal.Ext.ClipboardHistory.csproj", "{79775343-7A3D-445D-9104-3DD5B2893DF9}"
EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "CmdPalModuleInterface", "src\modules\cmdpal\CmdPalModuleInterface\CmdPalModuleInterface.vcxproj", "{0ADEB797-C8C7-4FFA-ACD5-2AF6CAD7ECD8}"
-EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WorkspacesCsharpLibrary", "src\modules\Workspaces\WorkspacesCsharpLibrary\WorkspacesCsharpLibrary.csproj", "{89D0E199-B17A-418C-B2F8-7375B6708357}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "NewPlus.ShellExtension.win10", "src\modules\NewPlus\NewShellExtensionContextMenu.win10\NewPlus.ShellExtension.win10.vcxproj", "{0DB0F63A-D2F8-4DA3-A650-2D0B8724218E}"
@@ -2427,14 +2425,6 @@ Global
{79775343-7A3D-445D-9104-3DD5B2893DF9}.Release|ARM64.Build.0 = Release|ARM64
{79775343-7A3D-445D-9104-3DD5B2893DF9}.Release|x64.ActiveCfg = Release|x64
{79775343-7A3D-445D-9104-3DD5B2893DF9}.Release|x64.Build.0 = Release|x64
- {0ADEB797-C8C7-4FFA-ACD5-2AF6CAD7ECD8}.Debug|ARM64.ActiveCfg = Debug|ARM64
- {0ADEB797-C8C7-4FFA-ACD5-2AF6CAD7ECD8}.Debug|ARM64.Build.0 = Debug|ARM64
- {0ADEB797-C8C7-4FFA-ACD5-2AF6CAD7ECD8}.Debug|x64.ActiveCfg = Debug|x64
- {0ADEB797-C8C7-4FFA-ACD5-2AF6CAD7ECD8}.Debug|x64.Build.0 = Debug|x64
- {0ADEB797-C8C7-4FFA-ACD5-2AF6CAD7ECD8}.Release|ARM64.ActiveCfg = Release|ARM64
- {0ADEB797-C8C7-4FFA-ACD5-2AF6CAD7ECD8}.Release|ARM64.Build.0 = Release|ARM64
- {0ADEB797-C8C7-4FFA-ACD5-2AF6CAD7ECD8}.Release|x64.ActiveCfg = Release|x64
- {0ADEB797-C8C7-4FFA-ACD5-2AF6CAD7ECD8}.Release|x64.Build.0 = Release|x64
{89D0E199-B17A-418C-B2F8-7375B6708357}.Debug|ARM64.ActiveCfg = Debug|ARM64
{89D0E199-B17A-418C-B2F8-7375B6708357}.Debug|ARM64.Build.0 = Debug|ARM64
{89D0E199-B17A-418C-B2F8-7375B6708357}.Debug|x64.ActiveCfg = Debug|x64
@@ -3207,7 +3197,6 @@ Global
{8FBDABA4-40EE-4C0E-9BC8-2F6444A6EF90} = {7520A2FE-00A2-49B8-83ED-DB216E874C04}
{C66020D1-CB10-4CF7-8715-84C97FD5E5E2} = {7520A2FE-00A2-49B8-83ED-DB216E874C04}
{79775343-7A3D-445D-9104-3DD5B2893DF9} = {ECB8E0D1-7603-4E5C-AB10-D1E545E6F8E2}
- {0ADEB797-C8C7-4FFA-ACD5-2AF6CAD7ECD8} = {3846508C-77EB-4034-A702-F8BB263C4F79}
{89D0E199-B17A-418C-B2F8-7375B6708357} = {A2221D7E-55E7-4BEA-90D1-4F162D670BBF}
{0DB0F63A-D2F8-4DA3-A650-2D0B8724218E} = {CA716AE6-FE5C-40AC-BB8F-2C87912687AC}
{453CBB73-A3CB-4D0B-8D24-6940B86FE21D} = {ECB8E0D1-7603-4E5C-AB10-D1E545E6F8E2}
diff --git a/src/RunnerV2/RunnerV2/Extensions/PackageVersionExtensions.cs b/src/RunnerV2/RunnerV2/Extensions/PackageVersionExtensions.cs
new file mode 100644
index 0000000000..b99570a427
--- /dev/null
+++ b/src/RunnerV2/RunnerV2/Extensions/PackageVersionExtensions.cs
@@ -0,0 +1,21 @@
+// 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.
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using Windows.ApplicationModel;
+
+namespace RunnerV2.Extensions
+{
+ internal static class PackageVersionExtensions
+ {
+ public static Version ToVersion(this PackageVersion packageVersion)
+ {
+ return new Version(packageVersion.Major, packageVersion.Minor, packageVersion.Build, packageVersion.Revision);
+ }
+ }
+}
diff --git a/src/RunnerV2/RunnerV2/Helpers/PackageHelper.cs b/src/RunnerV2/RunnerV2/Helpers/PackageHelper.cs
new file mode 100644
index 0000000000..2c277b84ae
--- /dev/null
+++ b/src/RunnerV2/RunnerV2/Helpers/PackageHelper.cs
@@ -0,0 +1,165 @@
+// 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.
+
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Reflection;
+using System.Runtime.InteropServices;
+using System.Runtime.InteropServices.ComTypes;
+using System.Runtime.InteropServices.Marshalling;
+using System.Text.RegularExpressions;
+using ManagedCommon;
+using ManagedCsWin32;
+using RunnerV2.Extensions;
+using Windows.ApplicationModel;
+using Windows.Foundation;
+using Windows.Management.Deployment;
+
+namespace RunnerV2.Helpers
+{
+ ///
+ /// Provides helper methods for working with UWP packages.
+ ///
+ internal static partial class PackageHelper
+ {
+ ///
+ /// Gets the registered UWP package based on the display name and version check.
+ ///
+ /// The display name of the package.
+ /// If true, the package version will be checked against the executing assembly version.
+ /// If a package is found the corresponding object. If none is found null.
+ internal static Package? GetRegisteredPackage(string packageDisplayName, bool checkVersion)
+ {
+ PackageManager packageManager = new();
+ foreach (var package in packageManager.FindPackagesForUser(null))
+ {
+ if (package.Id.FullName.Contains(packageDisplayName) && (!checkVersion || package.Id.Version.ToVersion() == Assembly.GetExecutingAssembly().GetName().Version))
+ {
+ return package;
+ }
+ }
+
+ return null;
+ }
+
+ internal static string[] FindMsixFiles(string directoryPath, bool recursive)
+ {
+ if (!Directory.Exists(directoryPath))
+ {
+ Logger.LogError("Tried to search msix files in " + directoryPath + ", but it does not exist.");
+ return [];
+ }
+
+ List matchedFiles = [];
+
+ try
+ {
+ foreach (string file in Directory.GetFiles(directoryPath, "*", recursive ? SearchOption.AllDirectories : SearchOption.TopDirectoryOnly))
+ {
+ if (File.Exists(file) && msixPackagePattern().IsMatch(Path.GetFileName(file)))
+ {
+ matchedFiles.Add(file);
+ }
+ }
+ }
+ catch (Exception e)
+ {
+ Logger.LogError("An error occured while searching for MSIX files.", e);
+ }
+
+ return [.. matchedFiles];
+ }
+
+ internal static bool RegisterPackage(string packagePath, string[] dependencies)
+ {
+ Logger.LogInfo("Starting package install of package \"" + packagePath + "\"");
+ PackageManager packageManager = new();
+ List uris = [];
+
+ foreach (string dependency in dependencies)
+ {
+ try
+ {
+ if (IsPackageSatisfied(dependency))
+ {
+ Logger.LogInfo("Dependency \"" + dependency + "\" is already satisfied.");
+ continue;
+ }
+ else
+ {
+ uris.Add(new Uri(packagePath));
+ }
+ }
+ catch (Exception ex)
+ {
+ Logger.LogError("Could not process dependency package at path \"" + dependency + "\"", ex);
+ }
+ }
+
+ try
+ {
+ IAsyncOperationWithProgress deploymentOperation = packageManager.AddPackageAsync(new Uri(packagePath), uris, DeploymentOptions.ForceApplicationShutdown);
+ deploymentOperation.Get();
+
+ switch (deploymentOperation.Status)
+ {
+ case AsyncStatus.Error:
+ Logger.LogError($"Registering {packagePath} failed. ErrorCode: {deploymentOperation.ErrorCode}, ErrorText: {deploymentOperation.GetResults().ErrorText}");
+ break;
+ case AsyncStatus.Canceled:
+ Logger.LogError($"Registering {packagePath} was canceled.");
+ break;
+ case AsyncStatus.Completed:
+ Logger.LogInfo($"Registering {packagePath} succeded.");
+ break;
+ default:
+ Logger.LogDebug($"Registering {packagePath} package started.");
+ break;
+ }
+
+ return true;
+ }
+ catch (Exception e)
+ {
+ Logger.LogError($"Exception thrown while trying to register package: {packagePath}", e);
+ }
+
+ return false;
+ }
+
+ private static bool IsPackageSatisfied(string packagePath)
+ {
+ if (!GetPackageNameAndVersionFromAppx(packagePath, out string name, out PackageVersion version))
+ {
+ Logger.LogError("Could not get package name and version from dependency package at path \"" + packagePath + "\"");
+ return false;
+ }
+
+ PackageManager packageManager = new();
+
+ foreach (var package in packageManager.FindPackagesForUser(null))
+ {
+ if (package.Id.Name.Equals(name, StringComparison.OrdinalIgnoreCase) &&
+ package.Id.Version.ToVersion() > version.ToVersion())
+ {
+ Logger.LogInfo($@"Package ""{name}"" is already statisfied with version: {package.Id.Version}. Target version: {version}. PackagePath: {packagePath}");
+ return true;
+ }
+ }
+
+ Logger.LogInfo($@"Package ""{name}"" with version {version} is not satisfied. PackagePath: {packagePath}");
+ return false;
+ }
+
+ private static bool GetPackageNameAndVersionFromAppx(string packagePath, out string name, out PackageVersion packageVersion)
+ {
+ // Todo: Implement this without interop if possible
+ return NativeMethods.GetPackageNameAndVersionFromAppx(packagePath, out name, out packageVersion);
+ }
+
+ [GeneratedRegex("(^.+\\.(appx|msix|msixbundle)$)", RegexOptions.IgnoreCase)]
+ private static partial Regex msixPackagePattern();
+ }
+}
diff --git a/src/RunnerV2/RunnerV2/ModuleInterfaces/CommandPaletteModuleInterface.cs b/src/RunnerV2/RunnerV2/ModuleInterfaces/CommandPaletteModuleInterface.cs
new file mode 100644
index 0000000000..933c15c41b
--- /dev/null
+++ b/src/RunnerV2/RunnerV2/ModuleInterfaces/CommandPaletteModuleInterface.cs
@@ -0,0 +1,136 @@
+// 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.
+
+using System;
+using System.Diagnostics;
+using System.IO;
+using System.Reflection;
+using System.Runtime.InteropServices;
+using System.Threading;
+using ManagedCommon;
+using Microsoft.PowerToys.Settings.UI.Library;
+using PowerToys.GPOWrapper;
+using RunnerV2.Helpers;
+using Windows.ApplicationModel;
+
+namespace RunnerV2.ModuleInterfaces
+{
+ internal sealed class CommandPaletteModuleInterface : IPowerToysModule
+ {
+ private const string PackageName = "Microsoft.CommandPalette"
+#if DEBUG
+ + ".Dev"
+#endif
+ ;
+
+ public string Name => "CmdPal";
+
+ public bool Enabled => new SettingsUtils().GetSettingsOrDefault().Enabled.CmdPal;
+
+ public GpoRuleConfigured GpoRuleConfigured => GPOWrapper.GetConfiguredCmdPalEnabledValue();
+
+ public void Disable()
+ {
+ ProcessHelper.ScheudleProcessKill("Microsoft.CmdPal.UI");
+ lock (_launchedLock)
+ {
+ _launched = false;
+ }
+ }
+
+ public void Enable()
+ {
+ if (PackageHelper.GetRegisteredPackage(PackageName, false) is null)
+ {
+ try
+ {
+ string architectureString = RuntimeInformation.ProcessArchitecture == Architecture.X64 ? "x64" : "ARM64";
+#if DEBUG
+ string[] msixFiles = PackageHelper.FindMsixFiles(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location) + "\\WinUI3Apps\\CmdPal\\AppPackages\\Microsoft.CmdPal.UI_0.0.1.0_Debug_Test\\", false);
+ string[] dependencies = PackageHelper.FindMsixFiles(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location) + "\\WinUI3Apps\\CmdPal\\AppPackages\\Microsoft.CmdPal.UI_0.0.1.0_Debug_Test\\Dependencies\\" + architectureString + "\\", true);
+#else
+ string[] msixFiles = PackageHelper.FindMsixFiles(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location) + "\\WinUI3Apps\\CmdPal\\", false);
+ string[] dependencies = PackageHelper.FindMsixFiles(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location) + "\\WinUI3Apps\\CmdPal\\Dependencies\\", true);
+#endif
+
+ if (msixFiles.Length > 0)
+ {
+ if (!PackageHelper.RegisterPackage(msixFiles[0], dependencies))
+ {
+ Logger.LogError("Failed to register Command Palette package.");
+ }
+ }
+ }
+ catch (Exception ex)
+ {
+ Logger.LogError("Exception occurred while enabling Command Palette package.", ex);
+ }
+ }
+
+ if (PackageHelper.GetRegisteredPackage(PackageName, false) is null)
+ {
+ Logger.LogError("Command Palette package is not registered after attempting to enable it.");
+ return;
+ }
+
+ lock (_launchedLock)
+ {
+ if (_launched)
+ {
+ return;
+ }
+ }
+
+ LaunchApp("explorer.exe", "x-cmdpal://background", false);
+ }
+
+ private readonly object _launchedLock = new();
+ private bool _launched;
+
+ // TODO: Implement retry logic for launching the app
+ /*private static void TryLaunch(string path, string args)
+ {
+ int baseDelay = 1000;
+ int maxAttempts = 9;
+ int retryCount = 0;
+
+ do
+ {
+ if (LaunchApp)
+ }
+ }*/
+
+ private bool LaunchApp(string path, string args, bool elevated)
+ {
+ try
+ {
+ Process? process = Process.Start(new ProcessStartInfo
+ {
+ FileName = path,
+ CreateNoWindow = true,
+ UseShellExecute = true,
+ Verb = elevated ? "runas" : "open",
+ Arguments = args,
+ });
+
+ if (process is null)
+ {
+ Logger.LogError($"Failed to start process for {path} with args {args}");
+ }
+ }
+ catch (Exception ex)
+ {
+ Logger.LogError($"Exception occurred while launching app {path} with args {args}", ex);
+ return false;
+ }
+
+ lock (_launchedLock)
+ {
+ _launched = true;
+ }
+
+ return true;
+ }
+ }
+}
diff --git a/src/RunnerV2/RunnerV2/ModuleInterfaces/IPowerToysModule.cs b/src/RunnerV2/RunnerV2/ModuleInterfaces/IPowerToysModule.cs
index e4498fa196..8363caeb35 100644
--- a/src/RunnerV2/RunnerV2/ModuleInterfaces/IPowerToysModule.cs
+++ b/src/RunnerV2/RunnerV2/ModuleInterfaces/IPowerToysModule.cs
@@ -13,22 +13,60 @@ namespace RunnerV2.ModuleInterfaces
{
public interface IPowerToysModule
{
+ ///
+ /// Gets the short name of the module. The same used as the name of the folder containing its settings.
+ ///
public string Name { get; }
+ ///
+ /// This function is called when the module is enabled.
+ ///
public void Enable();
+ ///
+ /// This function is called when the module is disabled.
+ ///
public void Disable();
+ ///
+ /// Gets a value indicating whether the module is enabled.
+ ///
+ ///
+ /// This value shall be read from the settings of the module in the module interface implementation.
+ ///
public bool Enabled { get; }
+ ///
+ /// Gets the GPO rule configured state for the module.
+ ///
+ ///
+ /// This value shall be read from the GPO settings with the class.
+ ///
public GpoRuleConfigured GpoRuleConfigured { get; }
+ ///
+ /// Gets a dictionary of hotkeys and their associated actions. Every hotkey must have an associated id.
+ ///
+ ///
+ /// If this property is not overridden, the module is considered to not have hotkeys.
+ ///
public Dictionary Hotkeys { get => []; }
+ ///
+ /// Gets a list of shortcuts, that shall be registered in the keyboard hook, and their associated actions.
+ ///
+ ///
+ /// If this property is not overridden, the module is considered to not have shortcuts.
+ ///
public List<(HotkeySettings Hotkey, Action Action)> Shortcuts { get => []; }
public Dictionary CustomActions { get => []; }
+ ///
+ /// This function is called when the settings of the module or the general settings are changed.
+ ///
+ /// Value of or "general" indicating the type of change.
+ /// The json element with the new settings.
public void OnSettingsChanged(string settingsKind, JsonElement jsonProperties)
{
}
diff --git a/src/RunnerV2/RunnerV2/NativeMethods.cs b/src/RunnerV2/RunnerV2/NativeMethods.cs
index d78a05933b..bbc0def459 100644
--- a/src/RunnerV2/RunnerV2/NativeMethods.cs
+++ b/src/RunnerV2/RunnerV2/NativeMethods.cs
@@ -5,7 +5,9 @@
using System;
using System.Drawing;
using System.Runtime.InteropServices;
+using System.Runtime.InteropServices.ComTypes;
using ManagedCommon;
+using Windows.ApplicationModel;
namespace RunnerV2
{
@@ -230,5 +232,27 @@ namespace RunnerV2
[DllImport("user32.dll")]
internal static extern uint SendInput(uint nInputs, NativeKeyboardHelper.INPUT[] pInputs, int cbSize);
+
+ public const int COINIT_MULTITHREADED = 0x0;
+
+ [LibraryImport("ole32.dll")]
+ public static partial int CoInitializeEx(IntPtr pvReserved, int dwCoInit);
+
+ [LibraryImport("ole32.dll")]
+ public static partial void CoUninitialize();
+
+ [DllImport("Shlwapi.dll")]
+ public static extern IntPtr SHCreateStreamOnFileEx(
+ [MarshalAs(UnmanagedType.LPWStr)] string pszFile,
+ uint grfMode,
+ [MarshalAs(UnmanagedType.Bool)]bool fCreate,
+ IntPtr pstmTemplate,
+ out IStream stream);
+
+ [DllImport("PowerToys.Interop.dll", CallingConvention = CallingConvention.Cdecl)]
+ internal static extern bool GetPackageNameAndVersionFromAppx(
+ [MarshalAs(UnmanagedType.LPWStr)] string appxPath,
+ [MarshalAs(UnmanagedType.LPWStr)] out string outName,
+ out PackageVersion outVersion);
}
}
diff --git a/src/RunnerV2/RunnerV2/Runner.cs b/src/RunnerV2/RunnerV2/Runner.cs
index 2c170fb869..a9ad773826 100644
--- a/src/RunnerV2/RunnerV2/Runner.cs
+++ b/src/RunnerV2/RunnerV2/Runner.cs
@@ -19,6 +19,7 @@ using ManagedCommon;
using RunnerV2.Helpers;
using RunnerV2.ModuleInterfaces;
using Update;
+using Windows.ApplicationModel;
using static RunnerV2.NativeMethods;
namespace RunnerV2
@@ -40,6 +41,7 @@ namespace RunnerV2
new AwakeModuleInterface(),
new CmdNotFoundModuleInterface(),
new ColorPickerModuleInterface(),
+ new CommandPaletteModuleInterface(),
];
internal static bool Run(Action afterInitializationAction)
diff --git a/src/RunnerV2/RunnerV2/RunnerV2.csproj b/src/RunnerV2/RunnerV2/RunnerV2.csproj
index 6776e6acc1..32a7eed81f 100644
--- a/src/RunnerV2/RunnerV2/RunnerV2.csproj
+++ b/src/RunnerV2/RunnerV2/RunnerV2.csproj
@@ -15,6 +15,7 @@
+
diff --git a/src/common/interop/PowerToys.Interop.vcxproj b/src/common/interop/PowerToys.Interop.vcxproj
index ca29e69cce..3378fba48c 100644
--- a/src/common/interop/PowerToys.Interop.vcxproj
+++ b/src/common/interop/PowerToys.Interop.vcxproj
@@ -93,6 +93,7 @@
+
CommonManaged.idl
diff --git a/src/common/interop/PowerToys.Interop.vcxproj.filters b/src/common/interop/PowerToys.Interop.vcxproj.filters
index 6fa51a3275..3f48175818 100644
--- a/src/common/interop/PowerToys.Interop.vcxproj.filters
+++ b/src/common/interop/PowerToys.Interop.vcxproj.filters
@@ -54,6 +54,9 @@
Header Files
+
+ Header Files
+
diff --git a/src/common/utils/package.h b/src/common/utils/package.h
index 138f3b8e5b..73ba876dc4 100644
--- a/src/common/utils/package.h
+++ b/src/common/utils/package.h
@@ -4,469 +4,124 @@
#include
#include
-#include
-#include
#include
-#include
#include
#include
-#include
-#include
-#include
#include "../logger/logger.h"
-#include "../version/version.h"
-namespace package
+using namespace winrt::Windows::Foundation;
+using Microsoft::WRL::ComPtr;
+
+struct PACKAGE_VERSION
{
- using namespace winrt::Windows::Foundation;
- using namespace winrt::Windows::ApplicationModel;
- using namespace winrt::Windows::Management::Deployment;
- using Microsoft::WRL::ComPtr;
+ UINT16 Major;
+ UINT16 Minor;
+ UINT16 Build;
+ UINT16 Revision;
+};
- inline BOOL IsWin11OrGreater()
+class ComInitializer
+{
+public:
+ explicit ComInitializer(DWORD coInitFlags = COINIT_MULTITHREADED) :
+ _initialized(false)
{
- OSVERSIONINFOEX osvi{};
- DWORDLONG dwlConditionMask = 0;
- byte op = VER_GREATER_EQUAL;
-
- // Initialize the OSVERSIONINFOEX structure.
- osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
- osvi.dwMajorVersion = HIBYTE(_WIN32_WINNT_WINTHRESHOLD);
- osvi.dwMinorVersion = LOBYTE(_WIN32_WINNT_WINTHRESHOLD);
- // Windows 11 build number
- osvi.dwBuildNumber = 22000;
-
- // Initialize the condition mask.
- VER_SET_CONDITION(dwlConditionMask, VER_MAJORVERSION, op);
- VER_SET_CONDITION(dwlConditionMask, VER_MINORVERSION, op);
- VER_SET_CONDITION(dwlConditionMask, VER_BUILDNUMBER, op);
-
- // Perform the test.
- return VerifyVersionInfo(
- &osvi,
- VER_MAJORVERSION | VER_MINORVERSION | VER_BUILDNUMBER,
- dwlConditionMask);
+ const HRESULT hr = CoInitializeEx(nullptr, coInitFlags);
+ _initialized = SUCCEEDED(hr);
}
- struct PACKAGE_VERSION
+ ~ComInitializer()
{
- UINT16 Major;
- UINT16 Minor;
- UINT16 Build;
- UINT16 Revision;
- };
+ if (_initialized)
+ {
+ CoUninitialize();
+ }
+ }
- class ComInitializer
+ bool Succeeded() const { return _initialized; }
+
+private:
+ bool _initialized;
+};
+
+__declspec(dllexport) EXTERN_C bool GetPackageNameAndVersionFromAppx(
+ const std::wstring& appxPath,
+ std::wstring& outName,
+ PACKAGE_VERSION& outVersion)
+{
+ try
{
- public:
- explicit ComInitializer(DWORD coInitFlags = COINIT_MULTITHREADED) :
- _initialized(false)
+ ComInitializer comInit;
+ if (!comInit.Succeeded())
{
- const HRESULT hr = CoInitializeEx(nullptr, coInitFlags);
- _initialized = SUCCEEDED(hr);
- }
-
- ~ComInitializer()
- {
- if (_initialized)
- {
- CoUninitialize();
- }
- }
-
- bool Succeeded() const { return _initialized; }
-
- private:
- bool _initialized;
- };
-
- inline bool GetPackageNameAndVersionFromAppx(
- const std::wstring& appxPath,
- std::wstring& outName,
- PACKAGE_VERSION& outVersion)
- {
- try
- {
- ComInitializer comInit;
- if (!comInit.Succeeded())
- {
- Logger::error(L"COM initialization failed.");
- return false;
- }
-
- ComPtr factory;
- ComPtr stream;
- ComPtr reader;
- ComPtr manifest;
- ComPtr packageId;
-
- HRESULT hr = CoCreateInstance(__uuidof(AppxFactory), nullptr, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&factory));
- if (FAILED(hr))
- return false;
-
- hr = SHCreateStreamOnFileEx(appxPath.c_str(), STGM_READ | STGM_SHARE_DENY_WRITE, FILE_ATTRIBUTE_NORMAL, FALSE, nullptr, &stream);
- if (FAILED(hr))
- return false;
-
- hr = factory->CreatePackageReader(stream.Get(), &reader);
- if (FAILED(hr))
- return false;
-
- hr = reader->GetManifest(&manifest);
- if (FAILED(hr))
- return false;
-
- hr = manifest->GetPackageId(&packageId);
- if (FAILED(hr))
- return false;
-
- LPWSTR name = nullptr;
- hr = packageId->GetName(&name);
- if (FAILED(hr))
- return false;
-
- UINT64 version = 0;
- hr = packageId->GetVersion(&version);
- if (FAILED(hr))
- return false;
-
- outName = std::wstring(name);
- CoTaskMemFree(name);
-
- outVersion.Major = static_cast((version >> 48) & 0xFFFF);
- outVersion.Minor = static_cast((version >> 32) & 0xFFFF);
- outVersion.Build = static_cast((version >> 16) & 0xFFFF);
- outVersion.Revision = static_cast(version & 0xFFFF);
-
- Logger::info(L"Package name: {}, version: {}.{}.{}.{}, appxPath: {}",
- outName,
- outVersion.Major,
- outVersion.Minor,
- outVersion.Build,
- outVersion.Revision,
- appxPath);
-
- return true;
- }
- catch (const std::exception& ex)
- {
- Logger::error(L"Standard exception: {}", winrt::to_hstring(ex.what()));
+ Logger::error(L"COM initialization failed.");
return false;
}
- catch (...)
- {
- Logger::error(L"Unknown or non-standard exception occurred.");
+
+ ComPtr factory;
+ ComPtr stream;
+ ComPtr reader;
+ ComPtr manifest;
+ ComPtr packageId;
+
+ HRESULT hr = CoCreateInstance(__uuidof(AppxFactory), nullptr, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&factory));
+ if (FAILED(hr))
return false;
- }
- }
-
- inline std::optional GetRegisteredPackage(std::wstring packageDisplayName, bool checkVersion)
- {
- PackageManager packageManager;
-
- for (const auto& package : packageManager.FindPackagesForUser({}))
- {
- const auto& packageFullName = std::wstring{ package.Id().FullName() };
- const auto& packageVersion = package.Id().Version();
-
- if (packageFullName.contains(packageDisplayName))
- {
- // If checkVersion is true, verify if the package has the same version as PowerToys.
- if ((!checkVersion) || (packageVersion.Major == VERSION_MAJOR && packageVersion.Minor == VERSION_MINOR && packageVersion.Revision == VERSION_REVISION))
- {
- return { package };
- }
- }
- }
-
- return {};
- }
-
- inline bool IsPackageRegisteredWithPowerToysVersion(std::wstring packageDisplayName)
- {
- return GetRegisteredPackage(packageDisplayName, true).has_value();
- }
-
- inline bool RegisterSparsePackage(const std::wstring& externalLocation, const std::wstring& sparsePkgPath)
- {
- try
- {
- Uri externalUri{ externalLocation };
- Uri packageUri{ sparsePkgPath };
-
- PackageManager packageManager;
-
- // Declare use of an external location
- AddPackageOptions options;
- options.ExternalLocationUri(externalUri);
- options.ForceUpdateFromAnyVersion(true);
-
- IAsyncOperationWithProgress deploymentOperation = packageManager.AddPackageByUriAsync(packageUri, options);
- deploymentOperation.get();
-
- // Check the status of the operation
- if (deploymentOperation.Status() == AsyncStatus::Error)
- {
- auto deploymentResult{ deploymentOperation.GetResults() };
- auto errorCode = deploymentOperation.ErrorCode();
- auto errorText = deploymentResult.ErrorText();
-
- Logger::error(L"Register {} package failed. ErrorCode: {}, ErrorText: {}", sparsePkgPath, std::to_wstring(errorCode), errorText);
- return false;
- }
- else if (deploymentOperation.Status() == AsyncStatus::Canceled)
- {
- Logger::error(L"Register {} package canceled.", sparsePkgPath);
- return false;
- }
- else if (deploymentOperation.Status() == AsyncStatus::Completed)
- {
- Logger::info(L"Register {} package completed.", sparsePkgPath);
- }
- else
- {
- Logger::debug(L"Register {} package started.", sparsePkgPath);
- }
-
- return true;
- }
- catch (std::exception& e)
- {
- Logger::error("Exception thrown while trying to register package: {}", e.what());
+ hr = SHCreateStreamOnFileEx(appxPath.c_str(), STGM_READ | STGM_SHARE_DENY_WRITE, FILE_ATTRIBUTE_NORMAL, FALSE, nullptr, &stream);
+ if (FAILED(hr))
return false;
- }
- }
- inline bool UnRegisterPackage(const std::wstring& pkgDisplayName)
- {
- try
- {
- PackageManager packageManager;
- const static auto packages = packageManager.FindPackagesForUser({});
-
- for (auto const& package : packages)
- {
- const auto& packageFullName = std::wstring{ package.Id().FullName() };
-
- if (packageFullName.contains(pkgDisplayName))
- {
- auto deploymentOperation{ packageManager.RemovePackageAsync(packageFullName) };
- deploymentOperation.get();
-
- // Check the status of the operation
- if (deploymentOperation.Status() == AsyncStatus::Error)
- {
- auto deploymentResult{ deploymentOperation.GetResults() };
- auto errorCode = deploymentOperation.ErrorCode();
- auto errorText = deploymentResult.ErrorText();
-
- Logger::error(L"Unregister {} package failed. ErrorCode: {}, ErrorText: {}", packageFullName, std::to_wstring(errorCode), errorText);
- }
- else if (deploymentOperation.Status() == AsyncStatus::Canceled)
- {
- Logger::error(L"Unregister {} package canceled.", packageFullName);
- }
- else if (deploymentOperation.Status() == AsyncStatus::Completed)
- {
- Logger::info(L"Unregister {} package completed.", packageFullName);
- }
- else
- {
- Logger::debug(L"Unregister {} package started.", packageFullName);
- }
-
- break;
- }
- }
- }
- catch (std::exception& e)
- {
- Logger::error("Exception thrown while trying to unregister package: {}", e.what());
+ hr = factory->CreatePackageReader(stream.Get(), &reader);
+ if (FAILED(hr))
return false;
- }
+
+ hr = reader->GetManifest(&manifest);
+ if (FAILED(hr))
+ return false;
+
+ hr = manifest->GetPackageId(&packageId);
+ if (FAILED(hr))
+ return false;
+
+ LPWSTR name = nullptr;
+ hr = packageId->GetName(&name);
+ if (FAILED(hr))
+ return false;
+
+ UINT64 version = 0;
+ hr = packageId->GetVersion(&version);
+ if (FAILED(hr))
+ return false;
+
+ outName = std::wstring(name);
+ CoTaskMemFree(name);
+
+ outVersion.Major = static_cast((version >> 48) & 0xFFFF);
+ outVersion.Minor = static_cast((version >> 32) & 0xFFFF);
+ outVersion.Build = static_cast((version >> 16) & 0xFFFF);
+ outVersion.Revision = static_cast(version & 0xFFFF);
+
+ Logger::info(L"Package name: {}, version: {}.{}.{}.{}, appxPath: {}",
+ outName,
+ outVersion.Major,
+ outVersion.Minor,
+ outVersion.Build,
+ outVersion.Revision,
+ appxPath);
return true;
}
-
- inline std::vector FindMsixFile(const std::wstring& directoryPath, bool recursive)
+ catch (const std::exception& ex)
{
- if (directoryPath.empty())
- {
- return {};
- }
-
- if (!std::filesystem::exists(directoryPath))
- {
- Logger::error(L"The directory '" + directoryPath + L"' does not exist.");
- return {};
- }
-
- const std::regex pattern(R"(^.+\.(appx|msix|msixbundle)$)", std::regex_constants::icase);
- std::vector matchedFiles;
-
- try
- {
- if (recursive)
- {
- for (const auto& entry : std::filesystem::recursive_directory_iterator(directoryPath))
- {
- if (entry.is_regular_file())
- {
- const auto& fileName = entry.path().filename().string();
- if (std::regex_match(fileName, pattern))
- {
- matchedFiles.push_back(entry.path());
- }
- }
- }
- }
- else
- {
- for (const auto& entry : std::filesystem::directory_iterator(directoryPath))
- {
- if (entry.is_regular_file())
- {
- const auto& fileName = entry.path().filename().string();
- if (std::regex_match(fileName, pattern))
- {
- matchedFiles.push_back(entry.path());
- }
- }
- }
- }
- }
- catch (const std::exception& ex)
- {
- Logger::error("An error occurred while searching for MSIX files: " + std::string(ex.what()));
- }
-
- return matchedFiles;
- }
-
- inline bool IsPackageSatisfied(const std::wstring& appxPath)
- {
- std::wstring targetName;
- PACKAGE_VERSION targetVersion{};
-
- if (!GetPackageNameAndVersionFromAppx(appxPath, targetName, targetVersion))
- {
- Logger::error(L"Failed to get package name and version from appx: " + appxPath);
- return false;
- }
-
- PackageManager pm;
-
- for (const auto& package : pm.FindPackagesForUser({}))
- {
- const auto& id = package.Id();
- if (std::wstring(id.Name()) == targetName)
- {
- const auto& version = id.Version();
-
- if (version.Major > targetVersion.Major ||
- (version.Major == targetVersion.Major && version.Minor > targetVersion.Minor) ||
- (version.Major == targetVersion.Major && version.Minor == targetVersion.Minor && version.Build > targetVersion.Build) ||
- (version.Major == targetVersion.Major && version.Minor == targetVersion.Minor && version.Build == targetVersion.Build && version.Revision >= targetVersion.Revision))
- {
- Logger::info(
- L"Package {} is already satisfied with version {}.{}.{}.{}; target version {}.{}.{}.{}; appxPath: {}",
- id.Name(),
- version.Major,
- version.Minor,
- version.Build,
- version.Revision,
- targetVersion.Major,
- targetVersion.Minor,
- targetVersion.Build,
- targetVersion.Revision,
- appxPath);
- return true;
- }
- }
- }
-
- Logger::info(
- L"Package {} is not satisfied. Target version: {}.{}.{}.{}; appxPath: {}",
- targetName,
- targetVersion.Major,
- targetVersion.Minor,
- targetVersion.Build,
- targetVersion.Revision,
- appxPath);
+ Logger::error(L"Standard exception: {}", winrt::to_hstring(ex.what()));
return false;
}
-
- inline bool RegisterPackage(std::wstring pkgPath, std::vector dependencies)
+ catch (...)
{
- try
- {
- Uri packageUri{ pkgPath };
-
- PackageManager packageManager;
-
- // Declare use of an external location
- DeploymentOptions options = DeploymentOptions::ForceTargetApplicationShutdown;
-
- Collections::IVector uris = winrt::single_threaded_vector();
- if (!dependencies.empty())
- {
- for (const auto& dependency : dependencies)
- {
- try
- {
- if (IsPackageSatisfied(dependency))
- {
- Logger::info(L"Dependency already satisfied: {}", dependency);
- }
- else
- {
- uris.Append(Uri(dependency));
- }
- }
- catch (const winrt::hresult_error& ex)
- {
- Logger::error(L"Error creating Uri for dependency: %s", ex.message().c_str());
- }
- }
- }
-
- IAsyncOperationWithProgress deploymentOperation = packageManager.AddPackageAsync(packageUri, uris, options);
- deploymentOperation.get();
-
- // Check the status of the operation
- if (deploymentOperation.Status() == AsyncStatus::Error)
- {
- auto deploymentResult{ deploymentOperation.GetResults() };
- auto errorCode = deploymentOperation.ErrorCode();
- auto errorText = deploymentResult.ErrorText();
-
- Logger::error(L"Register {} package failed. ErrorCode: {}, ErrorText: {}", pkgPath, std::to_wstring(errorCode), errorText);
- return false;
- }
- else if (deploymentOperation.Status() == AsyncStatus::Canceled)
- {
- Logger::error(L"Register {} package canceled.", pkgPath);
- return false;
- }
- else if (deploymentOperation.Status() == AsyncStatus::Completed)
- {
- Logger::info(L"Register {} package completed.", pkgPath);
- }
- else
- {
- Logger::debug(L"Register {} package started.", pkgPath);
- }
- }
- catch (std::exception& e)
- {
- Logger::error("Exception thrown while trying to register package: {}", e.what());
-
- return false;
- }
-
- return true;
+ Logger::error(L"Unknown or non-standard exception occurred.");
+ return false;
}
}
diff --git a/src/modules/cmdpal/CmdPalModuleInterface/CmdPalModuleInterface.vcxproj b/src/modules/cmdpal/CmdPalModuleInterface/CmdPalModuleInterface.vcxproj
deleted file mode 100644
index 433e7599d5..0000000000
--- a/src/modules/cmdpal/CmdPalModuleInterface/CmdPalModuleInterface.vcxproj
+++ /dev/null
@@ -1,88 +0,0 @@
-
-
-
-
-
- 17.0
- Win32Proj
- {0adeb797-c8c7-4ffa-acd5-2af6cad7ecd8}
- CmdPalModuleInterface
- 10.0
- PowerToys.CmdPalModuleInterface
-
-
-
- DynamicLibrary
- true
- v143
- Unicode
-
-
- DynamicLibrary
- false
- v143
- true
- Unicode
-
-
-
-
-
-
-
-
-
-
-
- ..\..\..\..\$(Platform)\$(Configuration)\
-
-
-
- {d9b8fc84-322a-4f9f-bbb9-20915c47ddfd}
-
-
- {6955446d-23f7-4023-9bb3-8657f904af99}
-
-
-
-
-
- EXAMPLEPOWERTOY_EXPORTS;_WINDOWS;_USRDLL;
- %(PreprocessorDefinitions);
-
-
- IS_DEV_BRANDING;%(PreprocessorDefinitions)
-
- ..\..\..\common\inc;..\..\..\common\Telemetry;..\..\;..\..\..\;%(AdditionalIncludeDirectories)
-
-
- $(OutDir)$(TargetName)$(TargetExt)
-
-
-
-
-
-
-
-
-
- Create
-
-
-
-
-
-
-
-
-
-
-
-
- This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.
-
-
-
-
-
diff --git a/src/modules/cmdpal/CmdPalModuleInterface/CmdPalModuleInterface.vcxproj.filters b/src/modules/cmdpal/CmdPalModuleInterface/CmdPalModuleInterface.vcxproj.filters
deleted file mode 100644
index 1b2723105d..0000000000
--- a/src/modules/cmdpal/CmdPalModuleInterface/CmdPalModuleInterface.vcxproj.filters
+++ /dev/null
@@ -1,33 +0,0 @@
-
-
-
-
- {4FC737F1-C7A5-4376-A066-2A32D752A2FF}
- cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx
-
-
- {93995380-89BD-4b04-88EB-625FBE52EBFB}
- h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd
-
-
- {67DA6AB6-F800-4c08-8B7A-83BB121AAD01}
- rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms
-
-
-
-
- Header Files
-
-
-
-
- Source Files
-
-
- Source Files
-
-
-
-
-
-
\ No newline at end of file
diff --git a/src/modules/cmdpal/CmdPalModuleInterface/dllmain.cpp b/src/modules/cmdpal/CmdPalModuleInterface/dllmain.cpp
deleted file mode 100644
index 7c6a7926db..0000000000
--- a/src/modules/cmdpal/CmdPalModuleInterface/dllmain.cpp
+++ /dev/null
@@ -1,355 +0,0 @@
-// dllmain.cpp : Defines the entry point for the DLL application.
-#include "pch.h"
-
-#include
-
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-
-HINSTANCE g_hInst_cmdPal = 0;
-
-BOOL APIENTRY DllMain(HMODULE hInstance,
- DWORD ul_reason_for_call,
- LPVOID)
-{
- switch (ul_reason_for_call)
- {
- case DLL_PROCESS_ATTACH:
- g_hInst_cmdPal = hInstance;
- break;
- case DLL_THREAD_ATTACH:
- case DLL_THREAD_DETACH:
- case DLL_PROCESS_DETACH:
- break;
- }
- return TRUE;
-}
-
-class CmdPal : public PowertoyModuleIface
-{
-private:
- std::wstring app_name;
-
- //contains the non localized key of the powertoy
- std::wstring app_key;
-
- HANDLE m_hTerminateEvent;
-
- // Track if this is the first call to enable
- bool firstEnableCall = true;
-
- static bool LaunchApp(const std::wstring& appPath, const std::wstring& commandLineArgs, bool elevated, bool silentFail)
- {
- std::wstring dir = std::filesystem::path(appPath).parent_path();
-
- SHELLEXECUTEINFO sei = { 0 };
- sei.cbSize = sizeof(SHELLEXECUTEINFO);
- sei.hwnd = nullptr;
- sei.fMask = SEE_MASK_NOCLOSEPROCESS | SEE_MASK_NO_CONSOLE;
- if (silentFail)
- {
- sei.fMask = sei.fMask | SEE_MASK_FLAG_NO_UI;
- }
- sei.lpVerb = elevated ? L"runas" : L"open";
- sei.lpFile = appPath.c_str();
- sei.lpParameters = commandLineArgs.c_str();
- sei.lpDirectory = dir.c_str();
- sei.nShow = SW_SHOWNORMAL;
-
- if (!ShellExecuteEx(&sei))
- {
- std::wstring error = get_last_error_or_default(GetLastError());
- Logger::error(L"Failed to launch process. {}", error);
- return false;
- }
-
- m_launched.store(true);
- return true;
- }
-
- std::vector GetProcessesIdByName(const std::wstring& processName)
- {
- std::vector processIds;
- HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
-
- if (snapshot != INVALID_HANDLE_VALUE)
- {
- PROCESSENTRY32 processEntry;
- processEntry.dwSize = sizeof(PROCESSENTRY32);
-
- if (Process32First(snapshot, &processEntry))
- {
- do
- {
- if (_wcsicmp(processEntry.szExeFile, processName.c_str()) == 0)
- {
- processIds.push_back(processEntry.th32ProcessID);
- }
- } while (Process32Next(snapshot, &processEntry));
- }
-
- CloseHandle(snapshot);
- }
-
- return processIds;
- }
-
- void TerminateCmdPal()
- {
- auto processIds = GetProcessesIdByName(L"Microsoft.CmdPal.UI.exe");
-
- if (processIds.size() == 0)
- {
- Logger::trace(L"Nothing To PROCESS_TERMINATE");
- return;
- }
-
- for (DWORD pid : processIds)
- {
- HANDLE hProcess = OpenProcess(SYNCHRONIZE | PROCESS_TERMINATE, FALSE, pid);
-
- if (hProcess != NULL)
- {
- SetEvent(m_hTerminateEvent);
-
- // Wait for 1.5 seconds for the process to end correctly, allowing time for ETW tracer and extensions to stop
- if (WaitForSingleObject(hProcess, 1500) == WAIT_TIMEOUT)
- {
- TerminateProcess(hProcess, 0);
- }
-
- CloseHandle(hProcess);
- }
- }
- }
-
-public:
- static std::atomic m_enabled;
- static std::atomic m_launched;
-
- CmdPal()
- {
- app_name = L"CmdPal";
- app_key = L"CmdPal";
- LoggerHelpers::init_logger(app_key, L"ModuleInterface", "CmdPal");
-
- m_hTerminateEvent = CreateDefaultEvent(CommonSharedConstants::CMDPAL_EXIT_EVENT);
- }
-
- ~CmdPal()
- {
- CmdPal::m_enabled.store(false);
- }
-
- // Destroy the powertoy and free memory
- virtual void destroy() override
- {
- Logger::trace("CmdPal::destroy()");
- TerminateCmdPal();
- delete this;
- }
-
- // Return the localized display name of the powertoy
- virtual const wchar_t* get_name() override
- {
- return app_name.c_str();
- }
-
- // Return the non localized key of the powertoy, this will be cached by the runner
- virtual const wchar_t* get_key() override
- {
- return app_key.c_str();
- }
-
- // Return the configured status for the gpo policy for the module
- virtual powertoys_gpo::gpo_rule_configured_t gpo_policy_enabled_configuration() override
- {
- return powertoys_gpo::getConfiguredCmdPalEnabledValue();
- }
-
- virtual bool get_config(wchar_t* buffer, int* buffer_size) override
- {
- HINSTANCE hinstance = reinterpret_cast(&__ImageBase);
-
- // Create a Settings object.
- PowerToysSettings::Settings settings(hinstance, get_name());
-
- return settings.serialize_to_buffer(buffer, buffer_size);
- }
-
- virtual void call_custom_action(const wchar_t* /*action*/) override
- {
- }
-
- virtual void set_config(const wchar_t* config) override
- {
- try
- {
- // Parse the input JSON string.
- PowerToysSettings::PowerToyValues values =
- PowerToysSettings::PowerToyValues::from_json_string(config, get_key());
-
- // If you don't need to do any custom processing of the settings, proceed
- // to persists the values calling:
- values.save_to_settings_file();
- // Otherwise call a custom function to process the settings before saving them to disk:
- // save_settings();
- }
- catch (std::exception&)
- {
- // Improper JSON.
- }
- }
-
- virtual void enable()
- {
- Logger::trace("CmdPal::enable()");
-
- CmdPal::m_enabled.store(true);
-
- std::wstring packageName = L"Microsoft.CommandPalette";
- // Launch CmdPal as normal user using explorer
- std::wstring launchPath = L"explorer.exe";
- std::wstring launchArgs = L"x-cmdpal://background";
-#ifdef IS_DEV_BRANDING
- packageName = L"Microsoft.CommandPalette.Dev";
-#endif
-
- if (!package::GetRegisteredPackage(packageName, false).has_value())
- {
- try
- {
- Logger::info(L"CmdPal not installed. Installing...");
-
- std::wstring installationFolder = get_module_folderpath();
-#ifdef _DEBUG
- std::wstring archSubdir = L"x64";
-#ifdef _M_ARM64
- archSubdir = L"ARM64";
-#endif
- auto msix = package::FindMsixFile(installationFolder + L"\\WinUI3Apps\\CmdPal\\AppPackages\\Microsoft.CmdPal.UI_0.0.1.0_Debug_Test\\", false);
- auto dependencies = package::FindMsixFile(installationFolder + L"\\WinUI3Apps\\CmdPal\\AppPackages\\Microsoft.CmdPal.UI_0.0.1.0_Debug_Test\\Dependencies\\" + archSubdir + L"\\", true);
-#else
- auto msix = package::FindMsixFile(installationFolder + L"\\WinUI3Apps\\CmdPal\\", false);
- auto dependencies = package::FindMsixFile(installationFolder + L"\\WinUI3Apps\\CmdPal\\Dependencies\\", true);
-#endif
-
- if (!msix.empty())
- {
- auto msixPath = msix[0];
-
- if (!package::RegisterPackage(msixPath, dependencies))
- {
- Logger::error(L"Failed to install CmdPal package");
- }
- }
- }
- catch (std::exception& e)
- {
- std::string errorMessage{ "Exception thrown while trying to install CmdPal package: " };
- errorMessage += e.what();
- Logger::error(errorMessage);
- }
- }
-
- if (!package::GetRegisteredPackage(packageName, false).has_value())
- {
- Logger::error("Cmdpal is not registered, quit..");
- return;
- }
-
- if (!firstEnableCall)
- {
- Logger::trace("Not first attempt, try to launch");
- LaunchApp(launchPath, launchArgs, false /*no elevated*/, false /*error pop up*/);
- }
- else
- {
- // If first time enable, do retry launch.
- Logger::trace("First attempt, try to launch");
- std::thread launchThread(&CmdPal::RetryLaunch, launchPath, launchArgs);
- launchThread.detach();
- }
-
- firstEnableCall = false;
- }
-
- virtual void disable()
- {
- Logger::trace("CmdPal::disable()");
- TerminateCmdPal();
-
- CmdPal::m_enabled.store(false);
- }
-
- static void RetryLaunch(std::wstring path, std::wstring cmdArgs)
- {
- const int base_delay_milliseconds = 1000;
- int max_retry = 9; // 2**9 - 1 seconds. Control total wait time within 10 min.
- int retry = 0;
- do
- {
- auto launch_result = LaunchApp(path, cmdArgs, false, retry < max_retry);
- if (launch_result)
- {
- Logger::info(L"CmdPal launched successfully after {} retries.", retry);
- return;
- }
- else
- {
- Logger::error(L"Retry {} launch CmdPal launch failed.", retry);
- }
-
- // When we got max retry, we don't need to wait for the next retry.
- if (retry < max_retry)
- {
- int delay = base_delay_milliseconds * (1 << (retry));
- std::this_thread::sleep_for(std::chrono::milliseconds(delay));
- }
- ++retry;
- } while (retry <= max_retry && m_enabled.load() && !m_launched.load());
-
- if (!m_enabled.load() || m_launched.load())
- {
- Logger::error(L"Retry cancelled. CmdPal is disabled or already launched.");
- }
- else
- {
- Logger::error(L"CmdPal launch failed after {} attempts.", retry);
- }
- }
-
- virtual bool on_hotkey(size_t) override
- {
- return false;
- }
-
- virtual size_t get_hotkeys(Hotkey*, size_t) override
- {
- return 0;
- }
-
- virtual bool is_enabled() override
- {
- return CmdPal::m_enabled.load();
- }
-};
-
-std::atomic CmdPal::m_enabled{ false };
-std::atomic CmdPal::m_launched{ false };
-
-extern "C" __declspec(dllexport) PowertoyModuleIface* __cdecl powertoy_create()
-{
- return new CmdPal();
-}
diff --git a/src/modules/cmdpal/CmdPalModuleInterface/packages.config b/src/modules/cmdpal/CmdPalModuleInterface/packages.config
deleted file mode 100644
index 09bfc449e2..0000000000
--- a/src/modules/cmdpal/CmdPalModuleInterface/packages.config
+++ /dev/null
@@ -1,4 +0,0 @@
-
-
-
-
\ No newline at end of file
diff --git a/src/modules/cmdpal/CmdPalModuleInterface/pch.cpp b/src/modules/cmdpal/CmdPalModuleInterface/pch.cpp
deleted file mode 100644
index 64b7eef6d6..0000000000
--- a/src/modules/cmdpal/CmdPalModuleInterface/pch.cpp
+++ /dev/null
@@ -1,5 +0,0 @@
-// pch.cpp: source file corresponding to the pre-compiled header
-
-#include "pch.h"
-
-// When you are using pre-compiled headers, this source file is necessary for compilation to succeed.
diff --git a/src/modules/cmdpal/CmdPalModuleInterface/pch.h b/src/modules/cmdpal/CmdPalModuleInterface/pch.h
deleted file mode 100644
index 30600d2e25..0000000000
--- a/src/modules/cmdpal/CmdPalModuleInterface/pch.h
+++ /dev/null
@@ -1,16 +0,0 @@
-// pch.h: This is a precompiled header file.
-// Files listed below are compiled only once, improving build performance for future builds.
-// This also affects IntelliSense performance, including code completion and many code browsing features.
-// However, files listed here are ALL re-compiled if any one of them is updated between builds.
-// Do not add files here that you will be updating frequently as this negates the performance advantage.
-
-#ifndef PCH_H
-#define PCH_H
-
-#include
-
-#include
-#include
-#include
-
-#endif //PCH_H