#include "pch.h" #include #include "powerpreview.h" #include "trace.h" #include "Generated Files/resource.h" #include #include #include #include #include #include // Constructor PowerPreviewModule::PowerPreviewModule() : m_moduleName(GET_RESOURCE_STRING(IDS_MODULE_NAME)), app_key(powerpreviewConstants::ModuleKey) { const std::wstring installationDir = get_module_folderpath(); std::filesystem::path logFilePath(PTSettingsHelper::get_module_save_folder_location(this->app_key)); logFilePath.append(LogSettings::fileExplorerLogPath); Logger::init(LogSettings::fileExplorerLoggerName, logFilePath.wstring(), PTSettingsHelper::get_log_settings_file_location()); Logger::info("Initializing PowerPreviewModule"); const bool installPerUser = true; m_fileExplorerModules.push_back({ .settingName = L"svg-previewer-toggle-setting", .settingDescription = GET_RESOURCE_STRING(IDS_PREVPANE_SVG_SETTINGS_DESCRIPTION), .checkModuleGPOEnabledRuleFunction = powertoys_gpo::getConfiguredSvgPreviewEnabledValue, .registryChanges = getSvgPreviewHandlerChangeSet(installationDir, installPerUser) }); m_fileExplorerModules.push_back({ .settingName = L"md-previewer-toggle-setting", .settingDescription = GET_RESOURCE_STRING(IDS_PREVPANE_MD_SETTINGS_DESCRIPTION), .checkModuleGPOEnabledRuleFunction = powertoys_gpo::getConfiguredMarkdownPreviewEnabledValue, .registryChanges = getMdPreviewHandlerChangeSet(installationDir, installPerUser) }); m_fileExplorerModules.push_back({ .settingName = L"monaco-previewer-toggle-setting", .settingDescription = GET_RESOURCE_STRING(IDS_PREVPANE_MONACO_SETTINGS_DESCRIPTION), .checkModuleGPOEnabledRuleFunction = powertoys_gpo::getConfiguredMonacoPreviewEnabledValue, .registryChanges = getMonacoPreviewHandlerChangeSet(installationDir, installPerUser) }); m_fileExplorerModules.push_back({ .settingName = L"pdf-previewer-toggle-setting", .settingDescription = GET_RESOURCE_STRING(IDS_PREVPANE_PDF_SETTINGS_DESCRIPTION), .checkModuleGPOEnabledRuleFunction = powertoys_gpo::getConfiguredPdfPreviewEnabledValue, .registryChanges = getPdfPreviewHandlerChangeSet(installationDir, installPerUser) }); m_fileExplorerModules.push_back({ .settingName = L"gcode-previewer-toggle-setting", .settingDescription = GET_RESOURCE_STRING(IDS_PREVPANE_GCODE_SETTINGS_DESCRIPTION), .checkModuleGPOEnabledRuleFunction = powertoys_gpo::getConfiguredGcodePreviewEnabledValue, .registryChanges = getGcodePreviewHandlerChangeSet(installationDir, installPerUser) }); m_fileExplorerModules.push_back({ .settingName = L"bgcode-previewer-toggle-setting", .settingDescription = GET_RESOURCE_STRING(IDS_PREVPANE_BGCODE_SETTINGS_DESCRIPTION), .checkModuleGPOEnabledRuleFunction = powertoys_gpo::getConfiguredBgcodePreviewEnabledValue, .registryChanges = getBgcodePreviewHandlerChangeSet(installationDir, installPerUser) }); m_fileExplorerModules.push_back({ .settingName = L"svg-thumbnail-toggle-setting", .settingDescription = GET_RESOURCE_STRING(IDS_SVG_THUMBNAIL_PROVIDER_SETTINGS_DESCRIPTION), .checkModuleGPOEnabledRuleFunction = powertoys_gpo::getConfiguredSvgThumbnailsEnabledValue, .registryChanges = getSvgThumbnailHandlerChangeSet(installationDir, installPerUser) }); m_fileExplorerModules.push_back({ .settingName = L"pdf-thumbnail-toggle-setting", .settingDescription = GET_RESOURCE_STRING(IDS_PDF_THUMBNAIL_PROVIDER_SETTINGS_DESCRIPTION), .checkModuleGPOEnabledRuleFunction = powertoys_gpo::getConfiguredPdfThumbnailsEnabledValue, .registryChanges = getPdfThumbnailHandlerChangeSet(installationDir, installPerUser) }); m_fileExplorerModules.push_back({ .settingName = L"gcode-thumbnail-toggle-setting", .settingDescription = GET_RESOURCE_STRING(IDS_GCODE_THUMBNAIL_PROVIDER_SETTINGS_DESCRIPTION), .checkModuleGPOEnabledRuleFunction = powertoys_gpo::getConfiguredGcodeThumbnailsEnabledValue, .registryChanges = getGcodeThumbnailHandlerChangeSet(installationDir, installPerUser) }); m_fileExplorerModules.push_back({ .settingName = L"bgcode-thumbnail-toggle-setting", .settingDescription = GET_RESOURCE_STRING(IDS_BGCODE_THUMBNAIL_PROVIDER_SETTINGS_DESCRIPTION), .checkModuleGPOEnabledRuleFunction = powertoys_gpo::getConfiguredBgcodeThumbnailsEnabledValue, .registryChanges = getBgcodeThumbnailHandlerChangeSet(installationDir, installPerUser) }); m_fileExplorerModules.push_back({ .settingName = L"stl-thumbnail-toggle-setting", .settingDescription = GET_RESOURCE_STRING(IDS_STL_THUMBNAIL_PROVIDER_SETTINGS_DESCRIPTION), .checkModuleGPOEnabledRuleFunction = powertoys_gpo::getConfiguredStlThumbnailsEnabledValue, .registryChanges = getStlThumbnailHandlerChangeSet(installationDir, installPerUser) }); m_fileExplorerModules.push_back({ .settingName = L"qoi-previewer-toggle-setting", .settingDescription = GET_RESOURCE_STRING(IDS_PREVPANE_QOI_SETTINGS_DESCRIPTION), .checkModuleGPOEnabledRuleFunction = powertoys_gpo::getConfiguredQoiPreviewEnabledValue, .registryChanges = getQoiPreviewHandlerChangeSet(installationDir, installPerUser) }); m_fileExplorerModules.push_back({ .settingName = L"qoi-thumbnail-toggle-setting", .settingDescription = GET_RESOURCE_STRING(IDS_QOI_THUMBNAIL_PROVIDER_SETTINGS_DESCRIPTION), .checkModuleGPOEnabledRuleFunction = powertoys_gpo::getConfiguredQoiThumbnailsEnabledValue, .registryChanges = getQoiThumbnailHandlerChangeSet(installationDir, installPerUser) }); try { PowerToysSettings::PowerToyValues settings = PowerToysSettings::PowerToyValues::load_from_settings_file(PowerPreviewModule::get_key()); apply_settings(settings); } catch (std::exception const& e) { Trace::InitSetErrorLoadingFile(e.what()); } } // Destroy the powertoy and free memory. void PowerPreviewModule::destroy() { Trace::Destroyed(); delete this; } // Return the localized display name of the powertoy const wchar_t* PowerPreviewModule::get_name() { return m_moduleName.c_str(); } // Return the non localized key of the powertoy, this will be cached by the runner const wchar_t* PowerPreviewModule::get_key() { return app_key.c_str(); } // Return JSON with the configuration options. bool PowerPreviewModule::get_config(_Out_ wchar_t* buffer, _Out_ int* buffer_size) { HINSTANCE hinstance = reinterpret_cast(&__ImageBase); // Create a Settings object. PowerToysSettings::Settings settings(hinstance, get_name()); // General Settings. settings.set_description(GET_RESOURCE_STRING(IDS_GENERAL_DESCRIPTION)); settings.set_icon_key(GET_RESOURCE_STRING(IDS_ICON_KEY_NAME)); settings.set_overview_link(L"https://aka.ms/PowerToysOverview_FileExplorerAddOns"); // Preview Pane: Settings Group Header. settings.add_header_szLarge( GET_RESOURCE_STRING(IDS_PRVPANE_FILE_PREV_STTNGS_GROUP_HEADER_ID), GET_RESOURCE_STRING(IDS_PRVPANE_FILE_PREV_STTNGS_GROUP_DESC), GET_RESOURCE_STRING(IDS_PRVPANE_FILE_PREV_STTNGS_GROUP_TEXT)); for (auto& fileExplorerModule : m_fileExplorerModules) { settings.add_bool_toggle( fileExplorerModule.settingName, fileExplorerModule.settingDescription, fileExplorerModule.registryChanges.isApplied()); } return settings.serialize_to_buffer(buffer, buffer_size); } // Called by the runner to pass the updated settings values as a serialized JSON. void PowerPreviewModule::set_config(const wchar_t* config) { try { auto settings = PowerToysSettings::PowerToyValues::from_json_string(config, get_key()); apply_settings(settings); settings.save_to_settings_file(); } catch (std::exception const& e) { Trace::SetConfigInvalidJSON(e.what()); } } void PowerPreviewModule::enable() { if (!m_enabled) { Trace::EnabledPowerPreview(true); } m_enabled = true; } // Disable active preview handlers. void PowerPreviewModule::disable() { for (auto& fileExplorerModule : m_fileExplorerModules) { if (!fileExplorerModule.registryChanges.unApply()) { Logger::error(L"Couldn't disable file explorer module {} during module disable() call", fileExplorerModule.settingName); } } if (m_enabled) { Trace::EnabledPowerPreview(false); } m_enabled = false; } // Returns if the powertoys is enabled bool PowerPreviewModule::is_enabled() { return m_enabled; } // Function to warn the user that PowerToys needs to run as administrator for changes to take effect void PowerPreviewModule::show_update_warning_message() { using namespace notifications; if (is_toast_disabled(PreviewModulesDontShowAgainRegistryPath, PreviewModulesDisableIntervalInDays)) { return; } std::vector actions = { link_button{ GET_RESOURCE_STRING(IDS_FILEEXPLORER_ADMIN_RESTART_WARNING_OPEN_SETTINGS), L"powertoys://open_settings/" }, link_button{ GET_RESOURCE_STRING(IDS_FILEEXPLORER_ADMIN_RESTART_WARNING_DONT_SHOW_AGAIN), L"powertoys://couldnt_toggle_powerpreview_modules_disable/" } }; show_toast_with_activations(GET_RESOURCE_STRING(IDS_FILEEXPLORER_ADMIN_RESTART_WARNING_DESCRIPTION), GET_RESOURCE_STRING(IDS_FILEEXPLORER_ADMIN_RESTART_WARNING_TITLE), {}, std::move(actions)); } void PowerPreviewModule::apply_settings(const PowerToysSettings::PowerToyValues& settings) { bool notifyShell = false; for (auto& fileExplorerModule : m_fileExplorerModules) { const auto toggle = settings.get_bool_value(fileExplorerModule.settingName); const auto gpo_rule = fileExplorerModule.checkModuleGPOEnabledRuleFunction(); const auto gpo_is_configured = gpo_rule == powertoys_gpo::gpo_rule_configured_enabled || gpo_rule == powertoys_gpo::gpo_rule_configured_disabled; if (gpo_rule == powertoys_gpo::gpo_rule_configured_unavailable) { Logger::warn(L"Couldn't read the gpo rule for Power Preview module {}", fileExplorerModule.settingName); } if (gpo_rule == powertoys_gpo::gpo_rule_configured_wrong_value) { Logger::warn(L"gpo rule for Power Preview module {} is set to an unknown value", fileExplorerModule.settingName); } // Skip if no need to update if (!toggle.has_value() && !gpo_is_configured) { continue; } bool module_new_state = false; if (toggle.has_value()) { module_new_state = *toggle; } if (gpo_is_configured) { // gpo rule overrides settings state module_new_state = gpo_rule == powertoys_gpo::gpo_rule_configured_enabled; } // Skip if no need to update if (module_new_state == fileExplorerModule.registryChanges.isApplied()) { continue; } // (Un)Apply registry changes depending on the new setting value const bool updated = module_new_state ? fileExplorerModule.registryChanges.apply() : fileExplorerModule.registryChanges.unApply(); if (updated) { notifyShell = true; Trace::PowerPreviewSettingsUpdated(fileExplorerModule.settingName.c_str(), !*toggle, *toggle, true); } else { Logger::error(L"Couldn't {} file explorer module {} during apply_settings", *toggle ? L"enable " : L"disable", fileExplorerModule.settingName); Trace::PowerPreviewSettingsUpdateFailed(fileExplorerModule.settingName.c_str(), !*toggle, *toggle, true); } } if (notifyShell) { SHChangeNotify(SHCNE_ASSOCCHANGED, SHCNF_IDLIST, NULL, NULL); } }