mirror of
https://github.com/microsoft/PowerToys.git
synced 2026-04-03 17:56:44 +02:00
## Summary of the Pull Request - Add the ability for users and admins (GPO) to control whether to display built in New on the context menu. - Changes to the setting are immediately reflected in the experience. - Built-in New is restored on uninstall. ## PR Checklist Note: Supersedes https://github.com/microsoft/PowerToys/pull/39843 - [x] **Closes**: [New+] Replace default New entry #37545 and Replace "New" with New+ option #37946 - [x] **Communication:** Discussed with @niels9001 - 1/22/2025 - [x] **Tests:** Completed manual test pass see highlight below - [x] **Localization:** All end-user-facing strings can be localized - [x] **Dev docs:** Updated "doc\devdocs\modules\newplus.md" - [n/a] **New binaries:** Added on the required places - [n/a] [JSON for signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json) for new binaries - [x] [WXS for installer] Updated installer (uninstall custom action) - [n/a] [YML for CI pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml) for new test projects - [n/a] [YML for signed pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml) - [No] **Documentation updated:** Pending, coming soon. (original PR https://github.com/MicrosoftDocs/windows-dev-docs/pull/5473) ## Detailed Description of the Pull Request / Additional comments Added the ability for users' admins' to display Windows built-in New or not I'm NOT aware of an official supported way to do this, so I'm achieving this by adding an invalid context menu handler in place of New in the Computer\HKEY_CURRENT_USER\Software\Classes\Directory\background\ShellEx\ContextMenuHandlers\New Changes are immediate, after applying the change, built-in New is shown/hidden accordingly Updates to New+ Settings UI New setting introduced to track user' preference (saved to newplus/settings.json) GPO setting introduced for control New visibility via GPO (GPO wins over user preference) Updates to New+ power_module.cpp When runner is running new plus will also apply built-in New admin GPO and user preference (GPO wins over user preference) to ensure correct behavior on setting restore and GPO application. Updates to installer Uninstall always reenable built-in "New" context menu Updated DevDoc Added a note on how to manually restore built-in New ## Validation Steps Performed Windows 11 x64 Settings UI New+ enabled New+ disabled GPO setting enabled GPO settings disabled Manually updating newplus/settings.json Windows 11 ARM64 I tested the reg hack manually, but didn't go through a full pass. Windows 10 x64 NOT tested. Windows 11, Settings, New+ Disabled and no GPO <img width="1040" height="1002" alt="image" src="https://github.com/user-attachments/assets/1b827b10-f009-4b0b-954f-d9311d40d201" /> Windows 11, Settings, New+ Enabled and no GPO <img width="1015" height="781" alt="image" src="https://github.com/user-attachments/assets/a5fa09d3-7fd3-4830-99a4-5f2ac9ce1a38" /> Hide built-in New: Off (the default) <img width="321" height="417" alt="image" src="https://github.com/user-attachments/assets/355fea60-bbb8-4f11-b648-291aaf0c4a6d" /> Hide built-in New: On <img width="1015" height="87" alt="image" src="https://github.com/user-attachments/assets/e83e45c4-6b67-443b-b045-26e7dda2cf46" /> Modern <img width="308" height="360" alt="image" src="https://github.com/user-attachments/assets/b164b240-6e67-410c-8481-7db3ee3225b7" /> Classic <img width="308" height="289" alt="image" src="https://github.com/user-attachments/assets/e2b6c262-a311-454c-9c76-40cb11ff2970" /> Disabling New+ also unhide New <img width="1031" height="569" alt="image" src="https://github.com/user-attachments/assets/29b8dae7-8190-4e64-b106-c6861e472a3d" /> <img width="308" height="353" alt="image" src="https://github.com/user-attachments/assets/e1977d6b-dc85-4db4-b9ab-c7bb2b27dde2" /> Windows 11, Settings, New+ Enabled and with GPO Hide built-in New: GPO enabled <img width="1020" height="691" alt="image" src="https://github.com/user-attachments/assets/75053ab8-92c6-4d38-b1b8-9b0d8293c207" /> Hide built-in New: GPO disabled <img width="1050" height="161" alt="image" src="https://github.com/user-attachments/assets/1a50b841-ff01-4662-a923-aee63717c834" />
198 lines
5.5 KiB
C++
198 lines
5.5 KiB
C++
#include "pch.h"
|
|
|
|
#include <filesystem>
|
|
#include <string>
|
|
|
|
#include <winrt/Windows.Data.Json.h>
|
|
|
|
#include <common/SettingsAPI/settings_objects.h>
|
|
#include <common/utils/gpo.h>
|
|
#include <common/utils/process_path.h>
|
|
#include <common/utils/resources.h>
|
|
#include <interface/powertoy_module_interface.h>
|
|
|
|
#include "constants.h"
|
|
#include "settings.h"
|
|
#include "trace.h"
|
|
#include "new_utilities.h"
|
|
#include "Generated Files/resource.h"
|
|
#include "RuntimeRegistration.h"
|
|
|
|
// Note: Settings are managed via Settings and UI Settings
|
|
class NewModule : public PowertoyModuleIface
|
|
{
|
|
private:
|
|
// Update registration based on enabled state
|
|
void UpdateRegistration(bool enabled)
|
|
{
|
|
if (enabled)
|
|
{
|
|
#if defined(ENABLE_REGISTRATION) || defined(NDEBUG)
|
|
NewPlusRuntimeRegistration::EnsureRegisteredWin10();
|
|
Logger::info(L"New+ context menu registered");
|
|
#endif
|
|
}
|
|
else
|
|
{
|
|
#if defined(ENABLE_REGISTRATION) || defined(NDEBUG)
|
|
NewPlusRuntimeRegistration::Unregister();
|
|
Logger::info(L"New+ context menu unregistered");
|
|
#endif
|
|
}
|
|
}
|
|
|
|
public:
|
|
NewModule()
|
|
{
|
|
init_settings();
|
|
}
|
|
|
|
virtual const wchar_t* get_name() override
|
|
{
|
|
static const std::wstring localized_context_menu_item =
|
|
GET_RESOURCE_STRING_FALLBACK(IDS_CONTEXT_MENU_ITEM_NEW, L"New+");
|
|
|
|
return localized_context_menu_item.c_str();
|
|
}
|
|
|
|
virtual const wchar_t* get_key() override
|
|
{
|
|
// This setting key must match EnabledModules.cs [JsonPropertyName("NewPlus")]
|
|
return newplus::constants::non_localizable::powertoy_key;
|
|
}
|
|
|
|
virtual powertoys_gpo::gpo_rule_configured_t gpo_policy_enabled_configuration() override
|
|
{
|
|
return powertoys_gpo::getConfiguredNewPlusEnabledValue();
|
|
}
|
|
|
|
virtual bool get_config(_Out_ PWSTR buffer, _Out_ int* buffer_size) override
|
|
{
|
|
// Not implemented as Settings are propagating via json
|
|
return true;
|
|
}
|
|
|
|
virtual void set_config(const wchar_t* config) override
|
|
{
|
|
// The following just checks to see if the Template Location was changed for metrics purposes
|
|
// Note: We are not saving the settings here and instead relying on read/write of json in Settings App .cs code paths
|
|
try
|
|
{
|
|
// Parse the input JSON string.
|
|
PowerToysSettings::PowerToyValues values =
|
|
PowerToysSettings::PowerToyValues::from_json_string(config, get_key());
|
|
|
|
values.save_to_settings_file();
|
|
NewSettingsInstance().Load();
|
|
|
|
auto templateValue = values.get_string_value(newplus::constants::non_localizable::settings_json_key_template_location);
|
|
if (templateValue.has_value())
|
|
{
|
|
const auto latest_location_value = templateValue.value();
|
|
const auto existing_location_value = NewSettingsInstance().GetTemplateLocation();
|
|
if (!newplus::utilities::wstring_same_when_comparing_ignore_case(latest_location_value, existing_location_value))
|
|
{
|
|
Trace::EventChangedTemplateLocation();
|
|
}
|
|
}
|
|
|
|
}
|
|
catch (std::exception& e)
|
|
{
|
|
Logger::error("Configuration parsing failed: {}", std::string{ e.what() });
|
|
}
|
|
}
|
|
|
|
virtual bool is_enabled_by_default() const override
|
|
{
|
|
return false;
|
|
}
|
|
|
|
virtual void enable() override
|
|
{
|
|
Logger::info("New+ enabled via Settings UI");
|
|
|
|
// Log telemetry
|
|
Trace::EventToggleOnOff(true);
|
|
if (package::IsWin11OrGreater())
|
|
{
|
|
newplus::utilities::register_msix_package();
|
|
}
|
|
|
|
powertoy_new_enabled = true;
|
|
UpdateRegistration(powertoy_new_enabled);
|
|
}
|
|
|
|
virtual void disable() override
|
|
{
|
|
Logger::info("New+ disabled via Settings UI");
|
|
Disable(true);
|
|
}
|
|
|
|
virtual bool is_enabled() override
|
|
{
|
|
return powertoy_new_enabled;
|
|
}
|
|
|
|
virtual void hide_file_extension(bool hide_file_extension)
|
|
{
|
|
Logger::info("New+ hide file extension {}", hide_file_extension);
|
|
}
|
|
|
|
virtual void hide_starting_digits(bool hide_starting_digits)
|
|
{
|
|
Logger::info("New+ hide starting digits {}", hide_starting_digits);
|
|
}
|
|
|
|
virtual void template_location(std::wstring path_location)
|
|
{
|
|
Logger::info("New+ template location");
|
|
}
|
|
|
|
virtual void destroy() override
|
|
{
|
|
Disable(false);
|
|
delete this;
|
|
}
|
|
|
|
private:
|
|
bool powertoy_new_enabled = false;
|
|
|
|
void Disable(bool const traceEvent)
|
|
{
|
|
// Log telemetry
|
|
if (traceEvent)
|
|
{
|
|
Trace::EventToggleOnOff(false);
|
|
}
|
|
powertoy_new_enabled = false;
|
|
UpdateRegistration(powertoy_new_enabled);
|
|
}
|
|
|
|
void init_settings()
|
|
{
|
|
powertoy_new_enabled = NewSettingsInstance().GetEnabled();
|
|
|
|
UpdateRegistration(powertoy_new_enabled);
|
|
|
|
if (powertoy_new_enabled)
|
|
{
|
|
// NOTE: This requires that the runner is running and have loaded the new plus module.
|
|
// It's not enough for user to just invoke the context menu.
|
|
if (NewSettingsInstance().GetHideBuiltInNew())
|
|
{
|
|
newplus::utilities::disable_built_in_new_via_registry();
|
|
}
|
|
else
|
|
{
|
|
newplus::utilities::enable_built_in_new_via_registry();
|
|
}
|
|
}
|
|
}
|
|
};
|
|
|
|
extern "C" __declspec(dllexport) PowertoyModuleIface* __cdecl powertoy_create()
|
|
{
|
|
return new NewModule();
|
|
}
|