mirror of
https://github.com/microsoft/PowerToys.git
synced 2025-12-30 17:07:23 +01:00
Compare commits
8 Commits
dev/vanzue
...
leilzh/tes
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
13e0d10048 | ||
|
|
4a129bbc6a | ||
|
|
e2a376f637 | ||
|
|
1a3d19b23a | ||
|
|
79c0946d34 | ||
|
|
8b6ce32a6d | ||
|
|
3e6eba342e | ||
|
|
d29e01f188 |
@@ -206,6 +206,11 @@
|
||||
<!-- Clean Video Conference Mute registry keys that might be around from previous installations. We've deprecated this utility since then. -->
|
||||
<Custom Action="CleanVideoConferenceRegistry" Before="InstallFinalize">NOT Installed</Custom>
|
||||
|
||||
<!-- User may have disabled the built-in New context menu via New+ -->
|
||||
<Custom Action="RestoreBuiltInNewContextMenu" Before="RemoveFiles">
|
||||
Installed AND (REMOVE="ALL")
|
||||
</Custom>
|
||||
|
||||
</InstallExecuteSequence>
|
||||
|
||||
<CustomAction Id="SetLaunchPowerToysParam"
|
||||
@@ -462,6 +467,14 @@
|
||||
DllEntry="InstallCmdPalPackageCA"
|
||||
/>
|
||||
|
||||
<CustomAction Id="RestoreBuiltInNewContextMenu"
|
||||
Return="ignore"
|
||||
Impersonate="yes"
|
||||
Execute="deferred"
|
||||
BinaryKey="PTCustomActions"
|
||||
DllEntry="RestoreBuiltInNewContextMenuCA"
|
||||
/>
|
||||
|
||||
<!-- Close 'PowerToys.exe' before uninstall-->
|
||||
<Property Id="MSIRESTARTMANAGERCONTROL" Value="DisableShutdown" />
|
||||
<Property Id="MSIFASTINSTALL" Value="DisableShutdown" />
|
||||
|
||||
@@ -1153,6 +1153,65 @@ UINT __stdcall UnRegisterContextMenuPackagesCA(MSIHANDLE hInstall)
|
||||
return WcaFinalize(er);
|
||||
}
|
||||
|
||||
UINT __stdcall RestoreBuiltInNewContextMenuCA(MSIHANDLE hInstall)
|
||||
{
|
||||
// Must be run as administrator to open and modify the registry.
|
||||
|
||||
HRESULT hr = S_OK;
|
||||
UINT er = ERROR_SUCCESS;
|
||||
|
||||
hr = WcaInitialize(hInstall, "RestoreBuiltInNewContextMenuCA");
|
||||
|
||||
try
|
||||
{
|
||||
const std::wstring builtInNewRegistryPath = LR"(Directory\Background\shellex\ContextMenuHandlers\New)";
|
||||
const std::wstring newDisabledValuePrefix = L"0_";
|
||||
|
||||
auto regDeleter = [](HKEY* regKeyHandle) { if (regKeyHandle && *regKeyHandle) RegCloseKey(*regKeyHandle); delete regKeyHandle; };
|
||||
std::unique_ptr<HKEY, decltype(regDeleter)> regKeyHandle(new HKEY(nullptr), regDeleter);
|
||||
|
||||
const LONG openStatus = RegOpenKeyExW(HKEY_CLASSES_ROOT, builtInNewRegistryPath.c_str(), 0, KEY_READ | KEY_WRITE, regKeyHandle.get());
|
||||
if (openStatus != ERROR_SUCCESS)
|
||||
{
|
||||
throw std::runtime_error("Failed to open New context menu registry key.");
|
||||
}
|
||||
|
||||
wchar_t buffer[256];
|
||||
DWORD bufferSize = sizeof(buffer);
|
||||
const LONG queryStatus = RegQueryValueExW(*regKeyHandle, nullptr, nullptr, nullptr, reinterpret_cast<LPBYTE>(buffer), &bufferSize);
|
||||
if (queryStatus != ERROR_SUCCESS)
|
||||
{
|
||||
throw std::runtime_error("Failed to read New context menu registry key.");
|
||||
}
|
||||
|
||||
const std::wstring builtInNewHandlerValue(buffer);
|
||||
const bool startsWithPrefix = builtInNewHandlerValue.find(newDisabledValuePrefix) == 0;
|
||||
|
||||
if (!startsWithPrefix)
|
||||
{
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
const std::wstring builtInNewEnabledValue = builtInNewHandlerValue.substr(newDisabledValuePrefix.length());
|
||||
const LONG setStatus = RegSetValueExW(*regKeyHandle, nullptr, 0, REG_SZ, reinterpret_cast<const BYTE*>(builtInNewEnabledValue.c_str()), static_cast<DWORD>((builtInNewEnabledValue.length() + 1)) * sizeof(wchar_t));
|
||||
if (setStatus != ERROR_SUCCESS)
|
||||
{
|
||||
throw std::runtime_error("Failed to update/restore the New context menu shell extension in the registry.");
|
||||
}
|
||||
}
|
||||
catch (const std::exception& e)
|
||||
{
|
||||
std::string errorMessage{ "Exception thrown while trying to restore built-in New: " };
|
||||
errorMessage += e.what();
|
||||
Logger::error(errorMessage);
|
||||
|
||||
er = ERROR_INSTALL_FAILURE;
|
||||
}
|
||||
|
||||
er = er == ERROR_SUCCESS ? (SUCCEEDED(hr) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE) : er;
|
||||
return WcaFinalize(er);
|
||||
}
|
||||
|
||||
UINT __stdcall TerminateProcessesCA(MSIHANDLE hInstall)
|
||||
{
|
||||
HRESULT hr = S_OK;
|
||||
|
||||
@@ -28,3 +28,4 @@ EXPORTS
|
||||
UninstallCommandNotFoundModuleCA
|
||||
UpgradeCommandNotFoundModuleCA
|
||||
UnsetAdvancedPasteAPIKeyCA
|
||||
RestoreBuiltInNewContextMenuCA
|
||||
|
||||
@@ -84,6 +84,15 @@
|
||||
<TextBlock x:Uid="NewPlus_Hide_Starting_Digits_Description" />
|
||||
</tkcontrols:SettingsCard.Description>
|
||||
</tkcontrols:SettingsCard>
|
||||
|
||||
<tkcontrols:SettingsCard x:Uid="NewPlus_Hide_BuiltIn_New_Toggle" IsEnabled="{x:Bind ViewModel.IsDisableBuiltInNewSettingsCardEnabled, Mode=OneWay}">
|
||||
<ToggleSwitch x:Uid="DisableBuiltInNewToggle" IsOn="{x:Bind ViewModel.HideBuiltInNew, Mode=TwoWay}" />
|
||||
</tkcontrols:SettingsCard>
|
||||
<InfoBar
|
||||
x:Uid="Elevation_Required"
|
||||
IsClosable="True"
|
||||
IsOpen="{x:Bind ViewModel.IsEnabledAndNotElevated, Mode=OneWay}"
|
||||
Severity="Informational" />
|
||||
</controls:SettingsGroup>
|
||||
|
||||
<controls:SettingsGroup x:Uid="NewPlus_behavior" IsEnabled="{x:Bind ViewModel.IsEnabled, Mode=OneWay}">
|
||||
|
||||
@@ -4434,6 +4434,10 @@ Activate by holding the key for the character you want to add an accent to, then
|
||||
<value>Ignores digits, spaces, and dots at the start of filenames—useful for sorting templates without showing those characters</value>
|
||||
<comment>Template filename starting digits settings toggle</comment>
|
||||
</data>
|
||||
<data name="NewPlus_Hide_BuiltIn_New_Toggle.Header" xml:space="preserve">
|
||||
<value>Hide the built-in New context menu</value>
|
||||
<comment>Localize New in accordance with Windows New</comment>
|
||||
</data>
|
||||
<data name="NewPlus_behavior.Header" xml:space="preserve">
|
||||
<value>Behavior</value>
|
||||
<comment>New+ behavior related settings label</comment>
|
||||
@@ -5127,4 +5131,7 @@ To record a specific window, enter the hotkey with the Alt key in the opposite m
|
||||
<data name="KeyBack" xml:space="preserve">
|
||||
<value>Back key</value>
|
||||
</data>
|
||||
<data name="Elevation_Required.Title" xml:space="preserve">
|
||||
<value>To change this setting you'll need to run PowerToys as administrator. You can restart PowerToys as administrator on the General page.</value>
|
||||
</data>
|
||||
</root>
|
||||
@@ -6,6 +6,7 @@ using System;
|
||||
using System.Diagnostics;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Security.Principal;
|
||||
using System.Text.Json;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
@@ -17,7 +18,7 @@ using Microsoft.PowerToys.Settings.UI.Library.Interfaces;
|
||||
using Microsoft.PowerToys.Settings.UI.Library.Utilities;
|
||||
using Microsoft.PowerToys.Settings.UI.Library.ViewModels.Commands;
|
||||
using Microsoft.PowerToys.Settings.UI.SerializationContext;
|
||||
|
||||
using Microsoft.Win32;
|
||||
using static Microsoft.PowerToys.Settings.UI.Helpers.ShellGetFolder;
|
||||
|
||||
namespace Microsoft.PowerToys.Settings.UI.ViewModels
|
||||
@@ -31,6 +32,9 @@ namespace Microsoft.PowerToys.Settings.UI.ViewModels
|
||||
private NewPlusSettings Settings { get; set; }
|
||||
|
||||
private const string ModuleName = NewPlusSettings.ModuleName;
|
||||
private const string BuiltInNewRegistryPath = @"HKEY_CLASSES_ROOT\Directory\Background\shellex\ContextMenuHandlers\New";
|
||||
private const string NewDisabledValuePrefix = "0_";
|
||||
private const string BuiltNewCOMGuid = "{D969A300-E7FF-11d0-A93B-00A0C90F2719}";
|
||||
|
||||
public NewPlusViewModel(ISettingsUtils settingsUtils, ISettingsRepository<GeneralSettings> settingsRepository, Func<string, int> ipcMSGCallBackFunc)
|
||||
{
|
||||
@@ -51,6 +55,8 @@ namespace Microsoft.PowerToys.Settings.UI.ViewModels
|
||||
InitializeEnabledValue();
|
||||
InitializeGpoValues();
|
||||
|
||||
_disableBuiltInNew = !IsBuiltInNewEnabled();
|
||||
|
||||
// set the callback functions value to handle outgoing IPC message.
|
||||
SendConfigMSG = ipcMSGCallBackFunc;
|
||||
}
|
||||
@@ -96,6 +102,8 @@ namespace Microsoft.PowerToys.Settings.UI.ViewModels
|
||||
OnPropertyChanged(nameof(IsHideFileExtSettingGPOConfigured));
|
||||
OnPropertyChanged(nameof(IsReplaceVariablesSettingGPOConfigured));
|
||||
OnPropertyChanged(nameof(IsReplaceVariablesSettingsCardEnabled));
|
||||
OnPropertyChanged(nameof(IsDisableBuiltInNewSettingsCardEnabled));
|
||||
OnPropertyChanged(nameof(IsEnabledAndNotElevated));
|
||||
|
||||
OutGoingGeneralSettings outgoingMessage = new OutGoingGeneralSettings(GeneralSettingsConfig);
|
||||
SendConfigMSG(outgoingMessage.ToString());
|
||||
@@ -110,6 +118,13 @@ namespace Microsoft.PowerToys.Settings.UI.ViewModels
|
||||
}
|
||||
}
|
||||
|
||||
private bool IsElevated()
|
||||
{
|
||||
WindowsIdentity identity = WindowsIdentity.GetCurrent();
|
||||
WindowsPrincipal principal = new WindowsPrincipal(identity);
|
||||
return principal.IsInRole(WindowsBuiltInRole.Administrator);
|
||||
}
|
||||
|
||||
public bool IsWin10OrLower
|
||||
{
|
||||
get => !OSVersionHelper.IsWindows11();
|
||||
@@ -164,6 +179,8 @@ namespace Microsoft.PowerToys.Settings.UI.ViewModels
|
||||
|
||||
public bool IsReplaceVariablesSettingGPOConfigured => _isNewPlusEnabled && _replaceVariablesIsGPOConfigured;
|
||||
|
||||
public bool IsDisableBuiltInNewSettingsCardEnabled => _isNewPlusEnabled && IsElevated();
|
||||
|
||||
public bool HideStartingDigits
|
||||
{
|
||||
get => _hideStartingDigits;
|
||||
@@ -206,11 +223,44 @@ namespace Microsoft.PowerToys.Settings.UI.ViewModels
|
||||
}
|
||||
}
|
||||
|
||||
public bool HideBuiltInNew
|
||||
{
|
||||
get
|
||||
{
|
||||
return _disableBuiltInNew;
|
||||
}
|
||||
|
||||
set
|
||||
{
|
||||
if (_disableBuiltInNew != value)
|
||||
{
|
||||
if (_disableBuiltInNew)
|
||||
{
|
||||
EnableBuiltInNew();
|
||||
}
|
||||
else
|
||||
{
|
||||
DisableBuiltInNew();
|
||||
}
|
||||
|
||||
_disableBuiltInNew = value;
|
||||
OnPropertyChanged(nameof(HideBuiltInNew));
|
||||
|
||||
NotifySettingsChanged();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsEnabledGpoConfigured
|
||||
{
|
||||
get => _enabledStateIsGPOConfigured;
|
||||
}
|
||||
|
||||
public bool IsEnabledAndNotElevated
|
||||
{
|
||||
get => _isNewPlusEnabled && !IsElevated();
|
||||
}
|
||||
|
||||
public ButtonClickCommand OpenCurrentNewTemplateFolder => new ButtonClickCommand(OpenNewTemplateFolder);
|
||||
|
||||
public ButtonClickCommand PickAnotherNewTemplateFolder => new ButtonClickCommand(PickNewTemplateFolder);
|
||||
@@ -271,6 +321,7 @@ namespace Microsoft.PowerToys.Settings.UI.ViewModels
|
||||
private bool _hideFileExtension;
|
||||
private bool _hideStartingDigits;
|
||||
private bool _replaceVariables;
|
||||
private bool _disableBuiltInNew;
|
||||
|
||||
private GpoRuleConfigured _enabledGpoRuleConfiguration;
|
||||
private bool _enabledStateIsGPOConfigured;
|
||||
@@ -317,5 +368,69 @@ namespace Microsoft.PowerToys.Settings.UI.ViewModels
|
||||
var hwnd = WinRT.Interop.WindowNative.GetWindowHandle(App.GetSettingsWindow());
|
||||
return await Task.FromResult(GetFolderDialogWithFlags(hwnd, FolderDialogFlags._BIF_NEWDIALOGSTYLE));
|
||||
}
|
||||
|
||||
private bool IsBuiltInNewEnabled()
|
||||
{
|
||||
try
|
||||
{
|
||||
string builtInNewHandlerValue = Registry.GetValue(BuiltInNewRegistryPath, string.Empty, null) as string;
|
||||
|
||||
return IsValidRegistryCOMFormatGuid(builtInNewHandlerValue);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.LogError("Failed to determine built-in New enablement status.", ex);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private static bool IsValidRegistryCOMFormatGuid(string input)
|
||||
{
|
||||
return Guid.TryParseExact(input, "B", out _);
|
||||
}
|
||||
|
||||
private void DisableBuiltInNew()
|
||||
{
|
||||
try
|
||||
{
|
||||
string builtInNewHandlerValue = Registry.GetValue(BuiltInNewRegistryPath, string.Empty, null) as string;
|
||||
|
||||
if (builtInNewHandlerValue.StartsWith(NewDisabledValuePrefix, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
// Already disabled
|
||||
return;
|
||||
}
|
||||
|
||||
Debug.Assert(builtInNewHandlerValue == BuiltNewCOMGuid, "Unexpected GUID encountered while disabling built-in New");
|
||||
string newDisabledValue = NewDisabledValuePrefix + builtInNewHandlerValue;
|
||||
Registry.SetValue(BuiltInNewRegistryPath, string.Empty, newDisabledValue);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.LogError("Failed to disable built-in New in the registry.", ex);
|
||||
MessageBox.Show(ex.Message);
|
||||
}
|
||||
}
|
||||
|
||||
private void EnableBuiltInNew()
|
||||
{
|
||||
try
|
||||
{
|
||||
string builtInNewHandlerValue = Registry.GetValue(BuiltInNewRegistryPath, string.Empty, null) as string;
|
||||
|
||||
if (builtInNewHandlerValue.StartsWith(NewDisabledValuePrefix, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
string newEnabledValue = builtInNewHandlerValue.Substring(NewDisabledValuePrefix.Length);
|
||||
Debug.Assert(newEnabledValue == BuiltNewCOMGuid, "Unexpected GUID encountered while reenabling built-in New");
|
||||
Registry.SetValue(BuiltInNewRegistryPath, string.Empty, newEnabledValue);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.LogError("Failed to enable built-in New in the registry.", ex);
|
||||
MessageBox.Show(ex.Message);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user