[File Explorer] Fix enable/disable for File Explorer PowerToy (#6883)

* Commented out enable/disable for File Explorer

* Revert UI changes

* Disable the toggles if PT is not running elevated

* Fixed compilation errors in tests

* Cleaned up preview pane code to separate thumbnail and preview panes as separate classes

* Fixed broken settings format and added elevation check and registry updated required logic. Preview Handler tested manually working, Thumbnail Enable/Disable needs to be fixed

* Updated Thumbnail enable/disable logic and added warning messages

* Update tests for File Explorer

* Fixed RegGetValue failing in Release config

* Renamed new classes

* Split wrappers for disable to work

* Modified enabled flag check to also check if user is on new settings. Fixed casing issue in powerpreview.h that caused a dialog prompt on first launch after install

* Update fontweight and margin

* Fixed release build not working

* Move UseNewSettings usage to powerpreview.cpp to avoid tests breaking. For new settings the enable check is done in constructor and for old settings it is done in enable

* Update src/core/Microsoft.PowerToys.Settings.UI/Strings/en-us/Resources.resw

Co-authored-by: htcfreek <61519853+htcfreek@users.noreply.github.com>

* Update src/core/Microsoft.PowerToys.Settings.UI/Strings/en-us/Resources.resw

Co-authored-by: htcfreek <61519853+htcfreek@users.noreply.github.com>

* Update src/core/Microsoft.PowerToys.Settings.UI/Strings/en-us/Resources.resw

Co-authored-by: htcfreek <61519853+htcfreek@users.noreply.github.com>

* Moved dup code to method

* Use correct versions of general settings for backwards compat test

Co-authored-by: htcfreek <61519853+htcfreek@users.noreply.github.com>
This commit is contained in:
Arjun Balgovind
2020-10-09 14:45:30 -07:00
committed by GitHub
parent d753179d1e
commit 7fd5e18ef4
22 changed files with 727 additions and 233 deletions

View File

@@ -11,7 +11,7 @@ namespace Microsoft.PowerToys.Settings.UI.Lib
{ {
public const string ModuleName = "File Explorer"; public const string ModuleName = "File Explorer";
[JsonPropertyName("Properties")] [JsonPropertyName("properties")]
public PowerPreviewProperties Properties { get; set; } public PowerPreviewProperties Properties { get; set; }
public PowerPreviewSettings() public PowerPreviewSettings()

View File

@@ -19,11 +19,16 @@ namespace Microsoft.PowerToys.Settings.UI.Lib.ViewModels
private string _settingsConfigFileFolder = string.Empty; private string _settingsConfigFileFolder = string.Empty;
public PowerPreviewViewModel(ISettingsRepository<PowerPreviewSettings> moduleSettingsRepository, Func<string, int> ipcMSGCallBackFunc, string configFileSubfolder = "") private GeneralSettings GeneralSettingsConfig { get; set; }
public PowerPreviewViewModel(ISettingsRepository<PowerPreviewSettings> moduleSettingsRepository, ISettingsRepository<GeneralSettings> generalSettingsRepository, Func<string, int> ipcMSGCallBackFunc, string configFileSubfolder = "")
{ {
// Update Settings file folder: // Update Settings file folder:
_settingsConfigFileFolder = configFileSubfolder; _settingsConfigFileFolder = configFileSubfolder;
// To obtain the general Settings configurations of PowerToys
GeneralSettingsConfig = generalSettingsRepository.SettingsConfig;
// To obtain the PowerPreview settings if it exists. // To obtain the PowerPreview settings if it exists.
// If the file does not exist, to create a new one and return the default settings configurations. // If the file does not exist, to create a new one and return the default settings configurations.
Settings = moduleSettingsRepository.SettingsConfig; Settings = moduleSettingsRepository.SettingsConfig;
@@ -99,6 +104,14 @@ namespace Microsoft.PowerToys.Settings.UI.Lib.ViewModels
return _settingsConfigFileFolder + "\\" + ModuleName; return _settingsConfigFileFolder + "\\" + ModuleName;
} }
public bool IsElevated
{
get
{
return GeneralSettingsConfig.IsElevated;
}
}
private void RaisePropertyChanged([CallerMemberName] string propertyName = null) private void RaisePropertyChanged([CallerMemberName] string propertyName = null)
{ {
// Notify UI of property change // Notify UI of property change

View File

@@ -20,10 +20,13 @@ namespace ViewModelTests
private Mock<ISettingsUtils> mockPowerPreviewSettingsUtils; private Mock<ISettingsUtils> mockPowerPreviewSettingsUtils;
private Mock<ISettingsUtils> mockGeneralSettingsUtils;
[TestInitialize] [TestInitialize]
public void SetUpStubSettingUtils() public void SetUpStubSettingUtils()
{ {
mockPowerPreviewSettingsUtils = ISettingsUtilsMocks.GetStubSettingsUtils<PowerPreviewSettings>(); mockPowerPreviewSettingsUtils = ISettingsUtilsMocks.GetStubSettingsUtils<PowerPreviewSettings>();
mockGeneralSettingsUtils = ISettingsUtilsMocks.GetStubSettingsUtils<GeneralSettings>();
} }
/// <summary> /// <summary>
@@ -42,11 +45,17 @@ namespace ViewModelTests
PowerPreviewSettings originalSettings = mockSettingsUtils.GetSettings<PowerPreviewSettings>(PowerPreviewSettings.ModuleName); PowerPreviewSettings originalSettings = mockSettingsUtils.GetSettings<PowerPreviewSettings>(PowerPreviewSettings.ModuleName);
var repository = new BackCompatTestProperties.MockSettingsRepository<PowerPreviewSettings>(mockSettingsUtils); var repository = new BackCompatTestProperties.MockSettingsRepository<PowerPreviewSettings>(mockSettingsUtils);
var mockGeneralIOProvider = BackCompatTestProperties.GetGeneralSettingsIOProvider(version);
var mockGeneralSettingsUtils = new SettingsUtils(mockGeneralIOProvider.Object);
GeneralSettings originalGeneralSettings = mockGeneralSettingsUtils.GetSettings<GeneralSettings>();
var generalSettingsRepository = new BackCompatTestProperties.MockSettingsRepository<GeneralSettings>(mockGeneralSettingsUtils);
// Initialise View Model with test Config files // Initialise View Model with test Config files
Func<string, int> SendMockIPCConfigMSG = msg => { return 0; }; Func<string, int> SendMockIPCConfigMSG = msg => { return 0; };
PowerPreviewViewModel viewModel = new PowerPreviewViewModel(repository, SendMockIPCConfigMSG); PowerPreviewViewModel viewModel = new PowerPreviewViewModel(repository, generalSettingsRepository, SendMockIPCConfigMSG);
// Verifiy that the old settings persisted // Verifiy that the old settings persisted
Assert.AreEqual(originalGeneralSettings.IsElevated, viewModel.IsElevated);
Assert.AreEqual(originalSettings.Properties.EnableMdPreview, viewModel.MDRenderIsEnabled); Assert.AreEqual(originalSettings.Properties.EnableMdPreview, viewModel.MDRenderIsEnabled);
Assert.AreEqual(originalSettings.Properties.EnableSvgPreview, viewModel.SVGRenderIsEnabled); Assert.AreEqual(originalSettings.Properties.EnableSvgPreview, viewModel.SVGRenderIsEnabled);
Assert.AreEqual(originalSettings.Properties.EnableSvgThumbnail, viewModel.SVGThumbnailIsEnabled); Assert.AreEqual(originalSettings.Properties.EnableSvgThumbnail, viewModel.SVGThumbnailIsEnabled);
@@ -69,7 +78,7 @@ namespace ViewModelTests
}; };
// arrange // arrange
PowerPreviewViewModel viewModel = new PowerPreviewViewModel(SettingsRepository<PowerPreviewSettings>.GetInstance(mockPowerPreviewSettingsUtils.Object), SendMockIPCConfigMSG, PowerPreviewSettings.ModuleName); PowerPreviewViewModel viewModel = new PowerPreviewViewModel(SettingsRepository<PowerPreviewSettings>.GetInstance(mockPowerPreviewSettingsUtils.Object), SettingsRepository<GeneralSettings>.GetInstance(mockGeneralSettingsUtils.Object), SendMockIPCConfigMSG, PowerPreviewSettings.ModuleName);
// act // act
viewModel.SVGRenderIsEnabled = true; viewModel.SVGRenderIsEnabled = true;
@@ -87,7 +96,7 @@ namespace ViewModelTests
}; };
// arrange // arrange
PowerPreviewViewModel viewModel = new PowerPreviewViewModel(SettingsRepository<PowerPreviewSettings>.GetInstance(mockPowerPreviewSettingsUtils.Object), SendMockIPCConfigMSG, PowerPreviewSettings.ModuleName); PowerPreviewViewModel viewModel = new PowerPreviewViewModel(SettingsRepository<PowerPreviewSettings>.GetInstance(mockPowerPreviewSettingsUtils.Object), SettingsRepository<GeneralSettings>.GetInstance(mockGeneralSettingsUtils.Object), SendMockIPCConfigMSG, PowerPreviewSettings.ModuleName);
// act // act
viewModel.SVGThumbnailIsEnabled = true; viewModel.SVGThumbnailIsEnabled = true;
@@ -105,7 +114,7 @@ namespace ViewModelTests
}; };
// arrange // arrange
PowerPreviewViewModel viewModel = new PowerPreviewViewModel(SettingsRepository<PowerPreviewSettings>.GetInstance(mockPowerPreviewSettingsUtils.Object), SendMockIPCConfigMSG, PowerPreviewSettings.ModuleName); PowerPreviewViewModel viewModel = new PowerPreviewViewModel(SettingsRepository<PowerPreviewSettings>.GetInstance(mockPowerPreviewSettingsUtils.Object), SettingsRepository<GeneralSettings>.GetInstance(mockGeneralSettingsUtils.Object), SendMockIPCConfigMSG, PowerPreviewSettings.ModuleName); ;
// act // act
viewModel.MDRenderIsEnabled = true; viewModel.MDRenderIsEnabled = true;

View File

@@ -759,4 +759,13 @@
<data name="FileExplorerPreview_PreviewPane_GroupSettings.Text" xml:space="preserve"> <data name="FileExplorerPreview_PreviewPane_GroupSettings.Text" xml:space="preserve">
<value>Preview Pane</value> <value>Preview Pane</value>
</data> </data>
<data name="FileExplorerPreview_RunAsAdminRequired.Text" xml:space="preserve">
<value>You need to run as administrator to modify these settings</value>
</data>
<data name="FileExplorerPreview_AffectsAllUsers.Text" xml:space="preserve">
<value>The settings on this page affect all users on the system</value>
</data>
<data name="FileExplorerPreview_RebootRequired.Text" xml:space="preserve">
<value>A reboot may be required for changes to these settings to take effect</value>
</data>
</root> </root>

View File

@@ -16,6 +16,7 @@
<Thickness x:Key="SmallLeftMargin">12, 0, 0, 0</Thickness> <Thickness x:Key="SmallLeftMargin">12, 0, 0, 0</Thickness>
<Thickness x:Key="SmallTopMargin">0, 12, 0, 0</Thickness> <Thickness x:Key="SmallTopMargin">0, 12, 0, 0</Thickness>
<Thickness x:Key="SmallTopBottomMargin">0, 12, 0, 12</Thickness> <Thickness x:Key="SmallTopBottomMargin">0, 12, 0, 12</Thickness>
<Thickness x:Key="SmallBottomMargin">0, 0, 0, 12</Thickness>
<Thickness x:Key="SmallLeftRightMargin">12, 0, 12, 0</Thickness> <Thickness x:Key="SmallLeftRightMargin">12, 0, 12, 0</Thickness>
<Thickness x:Key="SmallRightMargin">0, 0, 12, 0</Thickness> <Thickness x:Key="SmallRightMargin">0, 0, 12, 0</Thickness>
<Thickness x:Key="SmallLeftRightBottomMargin">12, 0, 12, 12</Thickness> <Thickness x:Key="SmallLeftRightBottomMargin">12, 0, 12, 12</Thickness>

View File

@@ -4,9 +4,14 @@
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:converters="using:Microsoft.Toolkit.Uwp.UI.Converters"
mc:Ignorable="d" mc:Ignorable="d"
Background="{ThemeResource ApplicationPageBackgroundThemeBrush}"> Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<Page.Resources>
<converters:BoolToObjectConverter x:Key="BoolToVisibilityConverter" TrueValue="Collapsed" FalseValue="Visible"/>
</Page.Resources>
<Grid RowSpacing="{StaticResource DefaultRowSpacing}"> <Grid RowSpacing="{StaticResource DefaultRowSpacing}">
<VisualStateManager.VisualStateGroups> <VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="LayoutVisualStates"> <VisualStateGroup x:Name="LayoutVisualStates">
@@ -43,25 +48,43 @@
<StackPanel Orientation="Vertical" <StackPanel Orientation="Vertical"
x:Name="PowerPreviewView"> x:Name="PowerPreviewView">
<TextBlock x:Uid="FileExplorerPreview_RunAsAdminRequired"
Foreground="{ThemeResource SystemControlErrorTextForegroundBrush}"
Visibility="{Binding Mode=OneWay, Path=IsElevated, Converter={StaticResource BoolToVisibilityConverter}}"
Margin="{StaticResource SmallBottomMargin}"/>
<TextBlock x:Uid="FileExplorerPreview_AffectsAllUsers"
Foreground="{x:Bind Mode=OneWay, Path=ViewModel.IsElevated, Converter={StaticResource ModuleEnabledToForegroundConverter}}"
Margin="{StaticResource SmallBottomMargin}"
FontWeight="SemiBold"/>
<TextBlock x:Uid="FileExplorerPreview_PreviewPane_GroupSettings" <TextBlock x:Uid="FileExplorerPreview_PreviewPane_GroupSettings"
Style="{StaticResource SettingsGroupTitleStyleAsHeader}" Style="{StaticResource SettingsGroupTitleStyleAsHeader}"
Foreground="{x:Bind Mode=OneWay, Path=IsEnabled, Converter={StaticResource ModuleEnabledToForegroundConverter}}"/> Foreground="{x:Bind Mode=OneWay, Path=ViewModel.IsElevated, Converter={StaticResource ModuleEnabledToForegroundConverter}}"/>
<ToggleSwitch x:Uid="FileExplorerPreview_ToggleSwitch_Preview_SVG" <ToggleSwitch x:Uid="FileExplorerPreview_ToggleSwitch_Preview_SVG"
Margin="{StaticResource SmallTopMargin}" Margin="{StaticResource SmallTopMargin}"
IsOn="{Binding Mode=TwoWay, Path=SVGRenderIsEnabled}" /> IsOn="{Binding Mode=TwoWay, Path=SVGRenderIsEnabled}"
IsEnabled="{Binding Mode=OneWay, Path=IsElevated}"/>
<ToggleSwitch x:Uid="FileExplorerPreview_ToggleSwitch_Preview_MD" <ToggleSwitch x:Uid="FileExplorerPreview_ToggleSwitch_Preview_MD"
Margin="{StaticResource SmallTopMargin}" Margin="{StaticResource SmallTopMargin}"
IsOn="{Binding Mode=TwoWay, Path=MDRenderIsEnabled}" /> IsOn="{Binding Mode=TwoWay, Path=MDRenderIsEnabled}"
IsEnabled="{Binding Mode=OneWay, Path=IsElevated}"/>
<TextBlock x:Uid="FileExplorerPreview_IconThumbnail_GroupSettings" <TextBlock x:Uid="FileExplorerPreview_IconThumbnail_GroupSettings"
Style="{StaticResource SettingsGroupTitleStyle}" Style="{StaticResource SettingsGroupTitleStyle}"
Foreground="{x:Bind Mode=OneWay, Path=IsEnabled, Converter={StaticResource ModuleEnabledToForegroundConverter}}"/> Foreground="{x:Bind Mode=OneWay, Path=ViewModel.IsElevated, Converter={StaticResource ModuleEnabledToForegroundConverter}}"/>
<TextBlock x:Uid="FileExplorerPreview_RebootRequired"
Foreground="{x:Bind Mode=OneWay, Path=ViewModel.IsElevated, Converter={StaticResource ModuleEnabledToForegroundConverter}}"
Margin="{StaticResource SmallTopBottomMargin}"
FontWeight="SemiBold"/>
<ToggleSwitch x:Uid="FileExplorerPreview_ToggleSwitch_SVG_Thumbnail" <ToggleSwitch x:Uid="FileExplorerPreview_ToggleSwitch_SVG_Thumbnail"
Margin="{StaticResource SmallTopMargin}" Margin="{StaticResource SmallTopMargin}"
IsOn="{Binding Mode=TwoWay, Path=SVGThumbnailIsEnabled}" /> IsOn="{Binding Mode=TwoWay, Path=SVGThumbnailIsEnabled}"
IsEnabled="{Binding Mode=OneWay, Path=IsElevated}"/>
</StackPanel> </StackPanel>
<RelativePanel x:Name="SidePanel" <RelativePanel x:Name="SidePanel"
HorizontalAlignment="Left" HorizontalAlignment="Left"

View File

@@ -20,7 +20,7 @@ namespace Microsoft.PowerToys.Settings.UI.Views
{ {
InitializeComponent(); InitializeComponent();
var settingsUtils = new SettingsUtils(new SystemIOProvider()); var settingsUtils = new SettingsUtils(new SystemIOProvider());
ViewModel = new PowerPreviewViewModel(SettingsRepository<PowerPreviewSettings>.GetInstance(settingsUtils), ShellPage.SendDefaultIPCMessage); ViewModel = new PowerPreviewViewModel(SettingsRepository<PowerPreviewSettings>.GetInstance(settingsUtils), SettingsRepository<GeneralSettings>.GetInstance(settingsUtils), ShellPage.SendDefaultIPCMessage);
DataContext = ViewModel; DataContext = ViewModel;
} }
} }

View File

@@ -156,4 +156,10 @@
<data name="Explr_Svg_Settings_Description" xml:space="preserve"> <data name="Explr_Svg_Settings_Description" xml:space="preserve">
<value>Render SVG images</value> <value>Render SVG images</value>
</data> </data>
<data name="FileExplorer_Admin_Restart_Warning_Description" xml:space="preserve">
<value>Some of the File Explorer modules could not be registered/unregistered as per your settings. Please restart PowerToys as admin for the changes to take place.</value>
</data>
<data name="FileExplorer_Admin_Restart_Warning_Title" xml:space="preserve">
<value>Failed to modify File Explorer modules</value>
</data>
</root> </root>

View File

@@ -5,39 +5,53 @@
#include "trace.h" #include "trace.h"
#include "settings.h" #include "settings.h"
#include "Generated Files/resource.h" #include "Generated Files/resource.h"
#include <common\os-detect.h>
// Constructor
PowerPreviewModule::PowerPreviewModule() :
m_moduleName(GET_RESOURCE_STRING(IDS_MODULE_NAME)),
m_fileExplorerModules(
{ // SVG Preview Handler settings object.
new PreviewHandlerSettings(
true,
L"svg-previewer-toggle-setting",
GET_RESOURCE_STRING(IDS_PREVPANE_SVG_SETTINGS_DESCRIPTION),
L"{ddee2b8a-6807-48a6-bb20-2338174ff779}",
L"Svg Preview Handler",
new RegistryWrapper()),
// MarkDown Preview Handler Settings Object.
new PreviewHandlerSettings(
true,
L"md-previewer-toggle-setting",
GET_RESOURCE_STRING(IDS_PREVPANE_MD_SETTINGS_DESCRIPTION),
L"{45769bcc-e8fd-42d0-947e-02beef77a1f5}",
L"Markdown Preview Handler",
new RegistryWrapper()),
//SVG Thumbnail Provider settings object.
new ThumbnailProviderSettings(
true,
L"svg-thumbnail-toggle-setting",
GET_RESOURCE_STRING(IDS_SVG_THUMBNAIL_PROVIDER_SETTINGS_DESCRIPTION),
L"{36B27788-A8BB-4698-A756-DF9F11F64F84}",
L"Svg Thumbnail Provider",
new RegistryWrapper(),
L".svg\\shellex\\{E357FCCD-A995-4576-B01F-234630154E96}") })
{
// Initialize the toggle states for each module
init_settings();
// If the user is on the new settings interface, File Explorer might be disabled if they updated from old to new settings, so initialize the registry state in the constructor as PowerPreviewModule::enable/disable will not be called on startup
if (UseNewSettings())
{
update_registry_to_match_toggles();
}
}
// Destroy the powertoy and free memory. // Destroy the powertoy and free memory.
void PowerPreviewModule::destroy() void PowerPreviewModule::destroy()
{ {
Trace::Destroyed(); Trace::Destroyed();
for (auto previewHandler : this->m_previewHandlers)
{
if (previewHandler != NULL)
{
// Disable all the active preview handlers.
if (this->m_enabled && previewHandler->GetToggleSettingState())
{
previewHandler->DisablePreview();
}
delete previewHandler;
}
}
for (auto thumbnailProvider : this->m_thumbnailProviders)
{
if (thumbnailProvider != NULL)
{
// Disable all the active thumbnail providers.
if (this->m_enabled && thumbnailProvider->GetToggleSettingState())
{
thumbnailProvider->DisablePreview();
}
delete thumbnailProvider;
}
}
delete this; delete this;
} }
@@ -66,20 +80,12 @@ bool PowerPreviewModule::get_config(_Out_ wchar_t* buffer, _Out_ int* buffer_siz
GET_RESOURCE_STRING(IDS_PRVPANE_FILE_PREV_STTNGS_GROUP_DESC), GET_RESOURCE_STRING(IDS_PRVPANE_FILE_PREV_STTNGS_GROUP_DESC),
GET_RESOURCE_STRING(IDS_PRVPANE_FILE_PREV_STTNGS_GROUP_TEXT)); GET_RESOURCE_STRING(IDS_PRVPANE_FILE_PREV_STTNGS_GROUP_TEXT));
for (auto previewHandler : this->m_previewHandlers) for (auto fileExplorerModule : this->m_fileExplorerModules)
{ {
settings.add_bool_toggle( settings.add_bool_toggle(
previewHandler->GetToggleSettingName(), fileExplorerModule->GetToggleSettingName(),
previewHandler->GetToggleSettingDescription(), fileExplorerModule->GetToggleSettingDescription(),
previewHandler->GetToggleSettingState()); fileExplorerModule->GetToggleSettingState());
}
for (auto thumbnailProvider : this->m_thumbnailProviders)
{
settings.add_bool_toggle(
thumbnailProvider->GetToggleSettingName(),
thumbnailProvider->GetToggleSettingDescription(),
thumbnailProvider->GetToggleSettingState());
} }
return settings.serialize_to_buffer(buffer, buffer_size); return settings.serialize_to_buffer(buffer, buffer_size);
@@ -92,14 +98,17 @@ void PowerPreviewModule::set_config(const wchar_t* config)
{ {
PowerToysSettings::PowerToyValues settings = PowerToysSettings::PowerToyValues::from_json_string(config); PowerToysSettings::PowerToyValues settings = PowerToysSettings::PowerToyValues::from_json_string(config);
for (auto previewHandler : this->m_previewHandlers) bool updateSuccess = true;
bool isElevated = is_process_elevated(false);
for (auto fileExplorerModule : this->m_fileExplorerModules)
{ {
previewHandler->UpdateState(settings, this->m_enabled); // If the user is using the new settings interface, as it does not have a toggle to modify enabled consider File Explorer to always be enabled
updateSuccess = updateSuccess && fileExplorerModule->UpdateState(settings, this->m_enabled || UseNewSettings(), isElevated);
} }
for (auto thumbnailProvider : this->m_thumbnailProviders) if (!updateSuccess)
{ {
thumbnailProvider->UpdateState(settings, this->m_enabled); show_update_warning_message();
} }
settings.save_to_settings_file(); settings.save_to_settings_file();
@@ -113,30 +122,10 @@ void PowerPreviewModule::set_config(const wchar_t* config)
// Enable preview handlers. // Enable preview handlers.
void PowerPreviewModule::enable() void PowerPreviewModule::enable()
{ {
for (auto previewHandler : this->m_previewHandlers) // Should only be done for old settings as it is already done for new settings in the constructor.
if (!UseNewSettings())
{ {
if (previewHandler->GetToggleSettingState()) update_registry_to_match_toggles();
{
// Enable all the previews with initial state set as true.
previewHandler->EnablePreview();
}
else
{
previewHandler->DisablePreview();
}
}
for (auto thumbnailProvider : this->m_thumbnailProviders)
{
if (thumbnailProvider->GetToggleSettingState())
{
// Enable all the thumbnail providers with initial state set as true.
thumbnailProvider->EnableThumbnailProvider();
}
else
{
thumbnailProvider->DisableThumbnailProvider();
}
} }
if (!this->m_enabled) if (!this->m_enabled)
@@ -150,15 +139,12 @@ void PowerPreviewModule::enable()
// Disable active preview handlers. // Disable active preview handlers.
void PowerPreviewModule::disable() void PowerPreviewModule::disable()
{ {
for (auto previewHandler : this->m_previewHandlers) elevation_check_wrapper([this]() {
for (auto fileExplorerModule : this->m_fileExplorerModules)
{ {
previewHandler->DisablePreview(); fileExplorerModule->Disable();
}
for (auto thumbnailProvider : this->m_thumbnailProviders)
{
thumbnailProvider->DisableThumbnailProvider();
} }
});
if (this->m_enabled) if (this->m_enabled)
{ {
@@ -184,14 +170,9 @@ void PowerPreviewModule::init_settings()
PowerToysSettings::PowerToyValues::load_from_settings_file(PowerPreviewModule::get_name()); PowerToysSettings::PowerToyValues::load_from_settings_file(PowerPreviewModule::get_name());
// Load settings states. // Load settings states.
for (auto previewHandler : this->m_previewHandlers) for (auto fileExplorerModule : this->m_fileExplorerModules)
{ {
previewHandler->LoadState(settings); fileExplorerModule->LoadState(settings);
}
for (auto thumbnailProvider : this->m_thumbnailProviders)
{
thumbnailProvider->LoadState(settings);
} }
} }
catch (std::exception const& e) catch (std::exception const& e)
@@ -199,3 +180,71 @@ void PowerPreviewModule::init_settings()
Trace::InitSetErrorLoadingFile(e.what()); Trace::InitSetErrorLoadingFile(e.what());
} }
} }
// Function to check if the registry states need to be updated
bool PowerPreviewModule::is_registry_update_required()
{
for (auto fileExplorerModule : this->m_fileExplorerModules)
{
if (fileExplorerModule->GetToggleSettingState() != fileExplorerModule->CheckRegistryState())
{
return true;
}
}
return false;
}
// Function to warn the user that PowerToys needs to run as administrator for changes to take effect
void PowerPreviewModule::show_update_warning_message()
{
// Show warning message if update is required
MessageBoxW(NULL,
GET_RESOURCE_STRING(IDS_FILEEXPLORER_ADMIN_RESTART_WARNING_DESCRIPTION).c_str(),
GET_RESOURCE_STRING(IDS_FILEEXPLORER_ADMIN_RESTART_WARNING_TITLE).c_str(),
MB_OK | MB_ICONWARNING);
}
// Function that checks if a registry method is required and if so checks if the process is elevated and accordingly executes the method or shows a warning
void PowerPreviewModule::registry_and_elevation_check_wrapper(std::function<void()> method)
{
// Check if a registry update is required
if (is_registry_update_required())
{
elevation_check_wrapper(method);
}
}
// Function that checks if the process is elevated and accordingly executes the method or shows a warning
void PowerPreviewModule::elevation_check_wrapper(std::function<void()> method)
{
// Check if the process is elevated in order to have permissions to modify HKLM registry
if (is_process_elevated(false))
{
method();
}
// Show a warning if it doesn't have permissions
else
{
show_update_warning_message();
}
}
// Function that updates the registry state to match the toggle states
void PowerPreviewModule::update_registry_to_match_toggles()
{
registry_and_elevation_check_wrapper([this]() {
for (auto fileExplorerModule : this->m_fileExplorerModules)
{
if (fileExplorerModule->GetToggleSettingState())
{
// Enable all the modules with initial state set as true.
fileExplorerModule->Enable();
}
else
{
fileExplorerModule->Disable();
}
}
});
}

View File

@@ -3,6 +3,8 @@
#include <common.h> #include <common.h>
#include "trace.h" #include "trace.h"
#include "settings.h" #include "settings.h"
#include "thumbnail_provider.h"
#include "preview_handler.h"
#include "registry_wrapper.h" #include "registry_wrapper.h"
using namespace PowerPreviewSettings; using namespace PowerPreviewSettings;
@@ -16,42 +18,25 @@ private:
// The PowerToy state. // The PowerToy state.
bool m_enabled = false; bool m_enabled = false;
std::wstring m_moduleName; std::wstring m_moduleName;
std::vector<FileExplorerPreviewSettings*> m_previewHandlers; std::vector<FileExplorerPreviewSettings*> m_fileExplorerModules;
std::vector<FileExplorerPreviewSettings*> m_thumbnailProviders;
// Function to check if the registry states need to be updated
bool is_registry_update_required();
// Function to warn the user that PowerToys needs to run as administrator for changes to take effect
void show_update_warning_message();
// Function that checks if a registry method is required and if so checks if the process is elevated and accordingly executes the method or shows a warning
void registry_and_elevation_check_wrapper(std::function<void()> method);
// Function that checks if the process is elevated and accordingly executes the method or shows a warning
void elevation_check_wrapper(std::function<void()> method);
// Function that updates the registry state to match the toggle states
void update_registry_to_match_toggles();
public: public:
PowerPreviewModule() : PowerPreviewModule();
m_moduleName(GET_RESOURCE_STRING(IDS_MODULE_NAME)),
m_previewHandlers(
{ // SVG Preview Handler settings object.
new FileExplorerPreviewSettings(
true,
L"svg-previewer-toggle-setting",
GET_RESOURCE_STRING(IDS_PREVPANE_SVG_SETTINGS_DESCRIPTION),
L"{ddee2b8a-6807-48a6-bb20-2338174ff779}",
L"SVG Preview Handler",
new RegistryWrapper()),
// MarkDown Preview Handler Settings Object.
new FileExplorerPreviewSettings(
true,
L"md-previewer-toggle-setting",
GET_RESOURCE_STRING(IDS_PREVPANE_MD_SETTINGS_DESCRIPTION),
L"{45769bcc-e8fd-42d0-947e-02beef77a1f5}",
L"Markdown Preview Handler",
new RegistryWrapper()) }),
m_thumbnailProviders(
{ // TODO: MOVE THIS SVG Thumbnail Provider settings object.
new FileExplorerPreviewSettings(
true,
L"svg-thumbnail-toggle-setting",
GET_RESOURCE_STRING(IDS_SVG_THUMBNAIL_PROVIDER_SETTINGS_DESCRIPTION),
L"{36B27788-A8BB-4698-A756-DF9F11F64F84}",
L"SVG Thumbnail Provider",
new RegistryWrapper()) })
{
init_settings();
};
virtual void destroy(); virtual void destroy();
virtual const wchar_t* get_name(); virtual const wchar_t* get_name();

View File

@@ -85,7 +85,7 @@
<IntrinsicFunctions>true</IntrinsicFunctions> <IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck> <SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>NDEBUG;EXAMPLEPOWERTOY_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions> <PreprocessorDefinitions>NDEBUG;EXAMPLEPOWERTOY_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories>..\..\..\common\Telemetry;..\..\..\common;..\..\common\inc;..\common\Telemetry;..\;..\..\;..\..\..\deps\cpprestsdk\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> <AdditionalIncludeDirectories>..\;..\..\..\common;..\..\..\common\telemetry;..\..\;..\..\..\;..\..\..\..\deps\cpprestsdk\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary> <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<LanguageStandard>stdcpplatest</LanguageStandard> <LanguageStandard>stdcpplatest</LanguageStandard>
</ClCompile> </ClCompile>
@@ -109,11 +109,13 @@
<ItemGroup> <ItemGroup>
<ClInclude Include="CLSID.h" /> <ClInclude Include="CLSID.h" />
<ClInclude Include="pch.h" /> <ClInclude Include="pch.h" />
<ClInclude Include="preview_handler.h" />
<ClInclude Include="registry_wrapper.h" /> <ClInclude Include="registry_wrapper.h" />
<ClInclude Include="registry_wrapper_interface.h" /> <ClInclude Include="registry_wrapper_interface.h" />
<ClInclude Include="Generated Files/resource.h" /> <ClInclude Include="Generated Files/resource.h" />
<None Include="resource.base.h" /> <None Include="resource.base.h" />
<ClInclude Include="settings.h" /> <ClInclude Include="settings.h" />
<ClInclude Include="thumbnail_provider.h" />
<ClInclude Include="trace.h" /> <ClInclude Include="trace.h" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
@@ -123,8 +125,10 @@
</ClCompile> </ClCompile>
<ClCompile Include="powerpreview.cpp" /> <ClCompile Include="powerpreview.cpp" />
<ClInclude Include="powerpreview.h" /> <ClInclude Include="powerpreview.h" />
<ClCompile Include="preview_handler.cpp" />
<ClCompile Include="registry_wrapper.cpp" /> <ClCompile Include="registry_wrapper.cpp" />
<ClCompile Include="settings.cpp" /> <ClCompile Include="settings.cpp" />
<ClCompile Include="thumbnail_provider.cpp" />
<ClCompile Include="trace.cpp" /> <ClCompile Include="trace.cpp" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>

View File

@@ -19,6 +19,12 @@
<ClCompile Include="trace.cpp"> <ClCompile Include="trace.cpp">
<Filter>Source Files</Filter> <Filter>Source Files</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="preview_handler.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="thumbnail_provider.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ClInclude Include="pch.h" /> <ClInclude Include="pch.h" />
@@ -43,6 +49,12 @@
<ClInclude Include="trace.h"> <ClInclude Include="trace.h">
<Filter>Header Files</Filter> <Filter>Header Files</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="preview_handler.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="thumbnail_provider.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<None Include="powerpreview.def" /> <None Include="powerpreview.def" />

View File

@@ -0,0 +1,53 @@
#include "pch.h"
#include "preview_handler.h"
namespace PowerPreviewSettings
{
const LPCWSTR PreviewHandlerSettings::preview_handlers_subkey = L"Software\\Microsoft\\Windows\\CurrentVersion\\PreviewHandlers";
// Function to enable the preview handler in registry
LONG PreviewHandlerSettings::Enable()
{
// Add registry value to enable preview.
return this->m_registryWrapper->SetRegistryValue(HKEY_LOCAL_MACHINE, preview_handlers_subkey, this->GetCLSID(), REG_SZ, (LPBYTE)this->GetRegistryValueData().c_str(), (DWORD)(this->GetRegistryValueData().length() * sizeof(wchar_t)));
}
// Function to disable the preview handler in registry
LONG PreviewHandlerSettings::Disable()
{
// Delete the registry key to disable preview.
return this->m_registryWrapper->DeleteRegistryValue(HKEY_LOCAL_MACHINE, preview_handlers_subkey, this->GetCLSID());
}
// Function to check if the preview handler is enabled in registry
bool PreviewHandlerSettings::CheckRegistryState()
{
DWORD dataType;
DWORD byteCount = 255;
wchar_t regValue[255] = { 0 };
LONG errorCode = this->m_registryWrapper->GetRegistryValue(HKEY_LOCAL_MACHINE, preview_handlers_subkey, this->GetCLSID(), &dataType, regValue, &byteCount);
// Registry value was found
if (errorCode == ERROR_SUCCESS)
{
// Check if the value type is string
if (dataType == REG_SZ)
{
// Check if the current registry value matches the expected value
if (wcscmp(regValue, this->GetRegistryValueData().c_str()) == 0)
{
return true;
}
}
}
return false;
}
// Function to retrieve the registry subkey
LPCWSTR PreviewHandlerSettings::GetSubkey()
{
return preview_handlers_subkey;
}
}

View File

@@ -0,0 +1,31 @@
#pragma once
#include "settings.h"
namespace PowerPreviewSettings
{
class PreviewHandlerSettings :
public FileExplorerPreviewSettings
{
private:
// Relative(HKLM/HKCU) sub key path of Preview Handlers list in registry. Registry key for Preview Handlers is generally HKLM\Software\Microsoft\Windows\CurrentVersion\PreviewHandlers, and the value name with CLSID of the handler in it is set to the name of the handler
static const LPCWSTR preview_handlers_subkey;
public:
PreviewHandlerSettings(bool toggleSettingEnabled, const std::wstring& toggleSettingName, const std::wstring& toggleSettingDescription, LPCWSTR clsid, const std::wstring& registryValueData, RegistryWrapperIface* registryWrapper) :
FileExplorerPreviewSettings(toggleSettingEnabled, toggleSettingName, toggleSettingDescription, clsid, registryValueData, registryWrapper)
{
}
// Function to enable the preview handler in registry
LONG Enable();
// Function to disable the preview handler in registry
LONG Disable();
// Function to check if the preview handler is enabled in registry
bool CheckRegistryState();
// Function to retrieve the registry subkey
static LPCWSTR GetSubkey();
};
}

View File

@@ -23,7 +23,7 @@ namespace PowerPreviewSettings
return err; return err;
} }
LONG RegistryWrapper::GetRegistryValue(HKEY keyScope, LPCWSTR subKey, LPCWSTR valueName, DWORD dwType, LPDWORD pdwType, PVOID pvData, LPDWORD pcbData) LONG RegistryWrapper::GetRegistryValue(HKEY keyScope, LPCWSTR subKey, LPCWSTR valueName, LPDWORD pdwType, PVOID pvData, LPDWORD pcbData)
{ {
HKEY OpenResult; HKEY OpenResult;
LONG err = RegOpenKeyExW(keyScope, subKey, 0, KEY_READ, &OpenResult); LONG err = RegOpenKeyExW(keyScope, subKey, 0, KEY_READ, &OpenResult);
@@ -61,4 +61,3 @@ namespace PowerPreviewSettings
return err; return err;
} }
} }

View File

@@ -8,6 +8,6 @@ namespace PowerPreviewSettings
public: public:
virtual LONG SetRegistryValue(HKEY keyScope, LPCWSTR subKey, LPCWSTR valueName, DWORD dwType, CONST BYTE* data, DWORD cbData); virtual LONG SetRegistryValue(HKEY keyScope, LPCWSTR subKey, LPCWSTR valueName, DWORD dwType, CONST BYTE* data, DWORD cbData);
virtual LONG DeleteRegistryValue(HKEY keyScope, LPCWSTR subKey, LPCWSTR valueName); virtual LONG DeleteRegistryValue(HKEY keyScope, LPCWSTR subKey, LPCWSTR valueName);
virtual LONG GetRegistryValue(HKEY keyScope, LPCWSTR subKey, LPCWSTR valueName, DWORD dwType, LPDWORD pdwType, PVOID pvData, LPDWORD pcbData); virtual LONG GetRegistryValue(HKEY keyScope, LPCWSTR subKey, LPCWSTR valueName, LPDWORD pdwType, PVOID pvData, LPDWORD pcbData);
}; };
} }

View File

@@ -10,5 +10,5 @@ public:
virtual LONG DeleteRegistryValue(HKEY keyScope, LPCWSTR subKey, LPCWSTR valueName) = 0; virtual LONG DeleteRegistryValue(HKEY keyScope, LPCWSTR subKey, LPCWSTR valueName) = 0;
// Reads a registry value. // Reads a registry value.
virtual LONG GetRegistryValue(HKEY keyScope, LPCWSTR subKey, LPCWSTR valueName, DWORD dwType, LPDWORD pdwType, PVOID pvData, LPDWORD pcbData) = 0; virtual LONG GetRegistryValue(HKEY keyScope, LPCWSTR subKey, LPCWSTR valueName, LPDWORD pdwType, PVOID pvData, LPDWORD pcbData) = 0;
}; };

View File

@@ -11,12 +11,6 @@ namespace PowerPreviewSettings
{ {
extern "C" IMAGE_DOS_HEADER __ImageBase; extern "C" IMAGE_DOS_HEADER __ImageBase;
// Relative(HKLM/HKCU) sub key path of Preview Handlers list in registry.
static LPCWSTR preview_handlers_subkey = L"Software\\Microsoft\\Windows\\CurrentVersion\\PreviewHandlers";
// Relative HKCR sub key path of SVG thumbnail provider in registry
static LPCWSTR svg_thumbnail_provider_subkey = L".svg\\shellex\\{E357FCCD-A995-4576-B01F-234630154E96}";
// Base Settings Class Implementation // Base Settings Class Implementation
FileExplorerPreviewSettings::FileExplorerPreviewSettings(bool toggleSettingEnabled, const std::wstring& toggleSettingName, const std::wstring& toggleSettingDescription, LPCWSTR clsid, const std::wstring& registryValueData, RegistryWrapperIface* registryWrapper) : FileExplorerPreviewSettings::FileExplorerPreviewSettings(bool toggleSettingEnabled, const std::wstring& toggleSettingName, const std::wstring& toggleSettingDescription, LPCWSTR clsid, const std::wstring& registryValueData, RegistryWrapperIface* registryWrapper) :
m_toggleSettingEnabled(toggleSettingEnabled), m_toggleSettingEnabled(toggleSettingEnabled),
@@ -66,7 +60,7 @@ namespace PowerPreviewSettings
return this->m_registryValueData; return this->m_registryValueData;
} }
// Load initial state of the Preview Handler. If no inital state present initialize setting with default value. // Load initial state of the file explorer module. If no inital state present initialize setting with default value.
void FileExplorerPreviewSettings::LoadState(PowerToysSettings::PowerToyValues& settings) void FileExplorerPreviewSettings::LoadState(PowerToysSettings::PowerToyValues& settings)
{ {
auto toggle = settings.get_bool_value(this->GetToggleSettingName()); auto toggle = settings.get_bool_value(this->GetToggleSettingName());
@@ -77,8 +71,8 @@ namespace PowerPreviewSettings
} }
} }
// Manage change in state of Preview Handler settings. // Manage change in state of file explorer module settings.
void FileExplorerPreviewSettings::UpdateState(PowerToysSettings::PowerToyValues& settings, bool enabled) bool FileExplorerPreviewSettings::UpdateState(PowerToysSettings::PowerToyValues& settings, bool enabled, bool isElevated)
{ {
auto toggle = settings.get_bool_value(this->GetToggleSettingName()); auto toggle = settings.get_bool_value(this->GetToggleSettingName());
if (toggle) if (toggle)
@@ -89,17 +83,22 @@ namespace PowerPreviewSettings
{ {
this->UpdateToggleSettingState(newState); this->UpdateToggleSettingState(newState);
// If global setting is enable. Add or remove the preview handler otherwise just change the UI and save the updated config. // If global setting is enable. Add or remove the file explorer module otherwise just change the UI and save the updated config.
if (enabled) if (enabled)
{
// Check if the registry state does not match the new state, registry needs to be modified
if (this->CheckRegistryState() != newState)
{
if (isElevated)
{ {
LONG err; LONG err;
if (lastState) if (lastState)
{ {
err = this->DisablePreview(); err = this->Disable();
} }
else else
{ {
err = this->EnablePreview(); err = this->Enable();
} }
if (err == ERROR_SUCCESS) if (err == ERROR_SUCCESS)
@@ -111,35 +110,21 @@ namespace PowerPreviewSettings
Trace::PowerPreviewSettingsUpdateFailed(this->GetToggleSettingName().c_str(), lastState, newState, enabled); Trace::PowerPreviewSettingsUpdateFailed(this->GetToggleSettingName().c_str(), lastState, newState, enabled);
} }
} }
// If process is not elevated, return false as it is not possible to update the registry
else
{
return false;
}
}
// If it matches the new state, no update to registry is required
}
else else
{ {
Trace::PowerPreviewSettingsUpdated(this->GetToggleSettingName().c_str(), lastState, newState, enabled); Trace::PowerPreviewSettingsUpdated(this->GetToggleSettingName().c_str(), lastState, newState, enabled);
} }
} }
} }
}
LONG FileExplorerPreviewSettings::EnablePreview() return true;
{
// Add registry value to enable preview.
return this->m_registryWrapper->SetRegistryValue(HKEY_CURRENT_USER, preview_handlers_subkey, this->GetCLSID(), REG_SZ, (LPBYTE)this->GetRegistryValueData().c_str(), (DWORD)(this->GetRegistryValueData().length() * sizeof(wchar_t)));
}
LONG FileExplorerPreviewSettings::DisablePreview()
{
// Delete the registry key to disable preview.
return this->m_registryWrapper->DeleteRegistryValue(HKEY_CURRENT_USER, preview_handlers_subkey, this->GetCLSID());
}
LONG FileExplorerPreviewSettings::EnableThumbnailProvider()
{
// Add registry value to enable thumbnail provider.
return this->m_registryWrapper->SetRegistryValue(HKEY_CURRENT_USER, svg_thumbnail_provider_subkey, this->GetCLSID(), REG_SZ, (LPBYTE)this->GetRegistryValueData().c_str(), (DWORD)(this->GetRegistryValueData().length() * sizeof(wchar_t)));
}
LONG FileExplorerPreviewSettings::DisableThumbnailProvider()
{
// Delete the registry key to disable thumbnail provider.
return this->m_registryWrapper->DeleteRegistryValue(HKEY_CURRENT_USER, svg_thumbnail_provider_subkey, this->GetCLSID());
} }
} }

View File

@@ -15,12 +15,14 @@ namespace PowerPreviewSettings
std::wstring m_toggleSettingName; std::wstring m_toggleSettingName;
std::wstring m_toggleSettingDescription; std::wstring m_toggleSettingDescription;
std::wstring m_registryValueData; std::wstring m_registryValueData;
RegistryWrapperIface * m_registryWrapper;
LPCWSTR m_clsid; LPCWSTR m_clsid;
protected:
RegistryWrapperIface* m_registryWrapper;
public: public:
FileExplorerPreviewSettings(bool toggleSettingEnabled, const std::wstring& toggleSettingName, const std::wstring& toggleSettingDescription, LPCWSTR clsid, const std::wstring& registryValueData, RegistryWrapperIface* registryWrapper); FileExplorerPreviewSettings(bool toggleSettingEnabled, const std::wstring& toggleSettingName, const std::wstring& toggleSettingDescription, LPCWSTR clsid, const std::wstring& registryValueData, RegistryWrapperIface* registryWrapper);
~ FileExplorerPreviewSettings(); ~FileExplorerPreviewSettings();
virtual bool GetToggleSettingState() const; virtual bool GetToggleSettingState() const;
virtual void UpdateToggleSettingState(bool state); virtual void UpdateToggleSettingState(bool state);
@@ -29,10 +31,9 @@ namespace PowerPreviewSettings
virtual LPCWSTR GetCLSID() const; virtual LPCWSTR GetCLSID() const;
virtual std::wstring GetRegistryValueData() const; virtual std::wstring GetRegistryValueData() const;
virtual void LoadState(PowerToysSettings::PowerToyValues& settings); virtual void LoadState(PowerToysSettings::PowerToyValues& settings);
virtual void UpdateState(PowerToysSettings::PowerToyValues& settings, bool enabled); virtual bool UpdateState(PowerToysSettings::PowerToyValues& settings, bool enabled, bool isElevated);
virtual LONG EnablePreview(); virtual LONG Enable() = 0;
virtual LONG DisablePreview(); virtual LONG Disable() = 0;
virtual LONG EnableThumbnailProvider(); virtual bool CheckRegistryState() = 0;
virtual LONG DisableThumbnailProvider();
}; };
} }

View File

@@ -0,0 +1,51 @@
#include "pch.h"
#include "thumbnail_provider.h"
namespace PowerPreviewSettings
{
// Function to enable the thumbnail provider in registry
LONG ThumbnailProviderSettings::Enable()
{
// Add registry value to enable thumbnail provider.
return this->m_registryWrapper->SetRegistryValue(HKEY_CLASSES_ROOT, thumbnail_provider_subkey, nullptr, REG_SZ, (LPBYTE)this->GetCLSID(), (DWORD)(wcslen(this->GetCLSID()) * sizeof(wchar_t)));
}
// Function to disable the thumbnail provider in registry
LONG ThumbnailProviderSettings::Disable()
{
// Delete the registry key to disable thumbnail provider.
return this->m_registryWrapper->DeleteRegistryValue(HKEY_CLASSES_ROOT, thumbnail_provider_subkey, nullptr);
}
// Function to check if the thumbnail provider is enabled in registry
bool ThumbnailProviderSettings::CheckRegistryState()
{
DWORD dataType;
DWORD byteCount = 255;
wchar_t regValue[255] = { 0 };
LONG errorCode = this->m_registryWrapper->GetRegistryValue(HKEY_CLASSES_ROOT, thumbnail_provider_subkey, nullptr, &dataType, regValue, &byteCount);
// Registry value was found
if (errorCode == ERROR_SUCCESS)
{
// Check if the value type is string
if (dataType == REG_SZ)
{
// Check if the current registry value matches the expected value
if (wcscmp(regValue, this->GetCLSID()) == 0)
{
return true;
}
}
}
return false;
}
// Function to retrieve the registry subkey
LPCWSTR ThumbnailProviderSettings::GetSubkey()
{
return thumbnail_provider_subkey;
}
}

View File

@@ -0,0 +1,31 @@
#pragma once
#include "settings.h"
namespace PowerPreviewSettings
{
class ThumbnailProviderSettings :
public FileExplorerPreviewSettings
{
private:
// Relative HKCR sub key path of thumbnail provider in registry. Registry key for Thumbnail Providers is generally HKCR\fileExtension\{E357FCCD-A995-4576-B01F-234630154E96}, and the default value in it is set to the CLSID of the provider
LPCWSTR thumbnail_provider_subkey;
public:
ThumbnailProviderSettings(bool toggleSettingEnabled, const std::wstring& toggleSettingName, const std::wstring& toggleSettingDescription, LPCWSTR clsid, const std::wstring& registryValueData, RegistryWrapperIface* registryWrapper, LPCWSTR subkey) :
FileExplorerPreviewSettings(toggleSettingEnabled, toggleSettingName, toggleSettingDescription, clsid, registryValueData, registryWrapper), thumbnail_provider_subkey(subkey)
{
}
// Function to enable the thumbnail provider in registry
LONG Enable();
// Function to disable the thumbnail provider in registry
LONG Disable();
// Function to check if the thumbnail provider is enabled in registry
bool CheckRegistryState();
// Function to retrieve the registry subkey
LPCWSTR GetSubkey();
};
}

View File

@@ -5,12 +5,14 @@
#include <powerpreview/trace.cpp> #include <powerpreview/trace.cpp>
#include <common.h> #include <common.h>
#include <powerpreview/registry_wrapper.h> #include <powerpreview/registry_wrapper.h>
#include <powerpreview/preview_handler.cpp>
#include <powerpreview/thumbnail_provider.cpp>
using namespace Microsoft::VisualStudio::CppUnitTestFramework; using namespace Microsoft::VisualStudio::CppUnitTestFramework;
using namespace PowerToysSettings; using namespace PowerToysSettings;
using namespace PowerPreviewSettings; using namespace PowerPreviewSettings;
namespace PreviewHandlerSettingsTest namespace FileExplorerPreviewSettingsTest
{ {
extern "C" IMAGE_DOS_HEADER __ImageBase; extern "C" IMAGE_DOS_HEADER __ImageBase;
@@ -22,10 +24,14 @@ namespace PreviewHandlerSettingsTest
HKEY Scope = NULL; HKEY Scope = NULL;
LPCWSTR SubKey; LPCWSTR SubKey;
LPCWSTR ValueName; LPCWSTR ValueName;
wchar_t ValueData[255] = { 0 };
}; };
class RegistryMock : public RegistryWrapperIface class RegistryMock : public RegistryWrapperIface
{ {
private:
wchar_t mockData[255] = { 0 };
public: public:
FunctionProperties SetRegistryMockProperties; FunctionProperties SetRegistryMockProperties;
FunctionProperties DeleteRegistryMockProperties; FunctionProperties DeleteRegistryMockProperties;
@@ -37,6 +43,7 @@ namespace PreviewHandlerSettingsTest
SetRegistryMockProperties.Scope = keyScope; SetRegistryMockProperties.Scope = keyScope;
SetRegistryMockProperties.SubKey = subKey; SetRegistryMockProperties.SubKey = subKey;
SetRegistryMockProperties.ValueName = valueName; SetRegistryMockProperties.ValueName = valueName;
wcscpy_s(SetRegistryMockProperties.ValueData, cbData, (WCHAR*)data);
return SetRegistryMockProperties.ReturnValue; return SetRegistryMockProperties.ReturnValue;
} }
@@ -49,26 +56,32 @@ namespace PreviewHandlerSettingsTest
return DeleteRegistryMockProperties.ReturnValue; return DeleteRegistryMockProperties.ReturnValue;
} }
LONG GetRegistryValue(HKEY keyScope, LPCWSTR subKey, LPCWSTR valueName, DWORD dwType, LPDWORD pdwType, PVOID pvData, LPDWORD pcbData) LONG GetRegistryValue(HKEY keyScope, LPCWSTR subKey, LPCWSTR valueName, LPDWORD pdwType, PVOID pvData, LPDWORD pcbData)
{ {
GetRegistryMockProperties.NumOfCalls++; GetRegistryMockProperties.NumOfCalls++;
GetRegistryMockProperties.Scope = keyScope; GetRegistryMockProperties.Scope = keyScope;
GetRegistryMockProperties.SubKey = subKey; GetRegistryMockProperties.SubKey = subKey;
GetRegistryMockProperties.ValueName = valueName; GetRegistryMockProperties.ValueName = valueName;
*pdwType = REG_SZ;
wcscpy_s((LPWSTR)pvData, 255, mockData);
return GetRegistryMockProperties.ReturnValue; return GetRegistryMockProperties.ReturnValue;
} }
void SetMockData(std::wstring data)
{
wcscpy_s(mockData, data.c_str());
}
}; };
TEST_CLASS(BaseSettingsTest) TEST_CLASS (BaseSettingsTest)
{ {
public: public:
TEST_METHOD (LoadState_ShouldLoadValidState_IfInitalStateIsPresent) TEST_METHOD (LoadState_ShouldLoadValidState_IfInitalStateIsPresent)
{ {
// Arrange // Arrange
bool defaultState = true; bool defaultState = true;
RegistryMock* mockRegistryWrapper = new RegistryMock(); RegistryMock* mockRegistryWrapper = new RegistryMock();
FileExplorerPreviewSettings previewSettings = GetSettingsObject(defaultState, mockRegistryWrapper); PreviewHandlerSettings previewSettings = GetPreviewHandlerSettingsObject(defaultState, mockRegistryWrapper);
auto settings = PowerToyValues::from_json_string(GetJSONSettings(previewSettings.GetToggleSettingName(), L"false")); auto settings = PowerToyValues::from_json_string(GetJSONSettings(previewSettings.GetToggleSettingName(), L"false"));
// Act // Act
@@ -83,7 +96,7 @@ namespace PreviewHandlerSettingsTest
// Arrange // Arrange
bool defaultState = true; bool defaultState = true;
RegistryMock* mockRegistryWrapper = new RegistryMock(); RegistryMock* mockRegistryWrapper = new RegistryMock();
FileExplorerPreviewSettings previewSettings = GetSettingsObject(defaultState, mockRegistryWrapper); PreviewHandlerSettings previewSettings = GetPreviewHandlerSettingsObject(defaultState, mockRegistryWrapper);
auto settings = PowerToyValues::from_json_string(L"{\"name\":\"Module Name\"}"); auto settings = PowerToyValues::from_json_string(L"{\"name\":\"Module Name\"}");
// Act // Act
@@ -93,50 +106,223 @@ namespace PreviewHandlerSettingsTest
Assert::AreEqual(previewSettings.GetToggleSettingState(), defaultState); Assert::AreEqual(previewSettings.GetToggleSettingState(), defaultState);
} }
TEST_METHOD (UpdateState_ShouldDisablePreview_IfPreviewsAreEnabledAndNewSettingsStateIsFalse) TEST_METHOD (PreviewHandlerSettingsUpdateState_ShouldDisableInRegistry_IfPreviewsAreEnabledAndNewSettingsStateIsFalseAndPowerToysIsElevatedAndRegistryContainsThePreview)
{ {
// Arrange // Arrange
bool enabled = true; bool enabled = true;
bool elevated = true;
RegistryMock* mockRegistryWrapper = new RegistryMock(); RegistryMock* mockRegistryWrapper = new RegistryMock();
FileExplorerPreviewSettings previewSettings = GetSettingsObject(true, mockRegistryWrapper); PreviewHandlerSettings previewSettings = GetPreviewHandlerSettingsObject(true, mockRegistryWrapper);
auto settings = PowerToyValues::from_json_string(GetJSONSettings(previewSettings.GetToggleSettingName(), L"false")); auto settings = PowerToyValues::from_json_string(GetJSONSettings(previewSettings.GetToggleSettingName(), L"false"));
previewSettings.UpdateToggleSettingState(true); previewSettings.UpdateToggleSettingState(true);
// Add expected data in registry
mockRegistryWrapper->SetMockData(previewSettings.GetRegistryValueData());
// Act // Act
previewSettings.UpdateState(settings, enabled); previewSettings.UpdateState(settings, enabled, elevated);
// Assert // Assert
Assert::IsFalse(previewSettings.GetToggleSettingState()); Assert::IsFalse(previewSettings.GetToggleSettingState());
Assert::AreEqual(mockRegistryWrapper->DeleteRegistryMockProperties.NumOfCalls, 1); Assert::AreEqual(mockRegistryWrapper->DeleteRegistryMockProperties.NumOfCalls, 1);
Assert::AreEqual(mockRegistryWrapper->GetRegistryMockProperties.NumOfCalls, 1);
} }
TEST_METHOD (UpdateState_ShouldEnablePreview_IfPreviewsAreEnabledAndNewSettingsStateIsTrue) TEST_METHOD (ThumbnailProviderSettingsUpdateState_ShouldDisableInRegistry_IfPreviewsAreEnabledAndNewSettingsStateIsFalseAndPowerToysIsElevatedAndRegistryContainsThePreview)
{ {
// Arrange // Arrange
bool enabled = true; bool enabled = true;
bool elevated = true;
RegistryMock* mockRegistryWrapper = new RegistryMock(); RegistryMock* mockRegistryWrapper = new RegistryMock();
FileExplorerPreviewSettings previewSettings = GetSettingsObject(true, mockRegistryWrapper); ThumbnailProviderSettings thumbnailSettings = GetThumbnailProviderSettingsObject(true, mockRegistryWrapper);
auto settings = PowerToyValues::from_json_string(GetJSONSettings(thumbnailSettings.GetToggleSettingName(), L"false"));
thumbnailSettings.UpdateToggleSettingState(true);
// Add expected data in registry
mockRegistryWrapper->SetMockData(thumbnailSettings.GetCLSID());
// Act
thumbnailSettings.UpdateState(settings, enabled, elevated);
// Assert
Assert::IsFalse(thumbnailSettings.GetToggleSettingState());
Assert::AreEqual(mockRegistryWrapper->DeleteRegistryMockProperties.NumOfCalls, 1);
Assert::AreEqual(mockRegistryWrapper->GetRegistryMockProperties.NumOfCalls, 1);
}
TEST_METHOD (UpdateState_ShouldNotDisableInRegistry_IfPreviewsAreEnabledAndNewSettingsStateIsFalseAndPowerToysIsElevatedAndRegistryDoesNotContainThePreview)
{
// Arrange
bool enabled = true;
bool elevated = true;
RegistryMock* mockRegistryWrapper = new RegistryMock();
PreviewHandlerSettings previewSettings = GetPreviewHandlerSettingsObject(true, mockRegistryWrapper);
auto settings = PowerToyValues::from_json_string(GetJSONSettings(previewSettings.GetToggleSettingName(), L"false"));
previewSettings.UpdateToggleSettingState(true);
// Act
previewSettings.UpdateState(settings, enabled, elevated);
// Assert
Assert::IsFalse(previewSettings.GetToggleSettingState());
Assert::AreEqual(mockRegistryWrapper->DeleteRegistryMockProperties.NumOfCalls, 0);
Assert::AreEqual(mockRegistryWrapper->GetRegistryMockProperties.NumOfCalls, 1);
}
TEST_METHOD (UpdateState_ShouldNotDisableInRegistry_IfPreviewsAreEnabledAndNewSettingsStateIsFalseAndPowerToysIsNotElevated)
{
// Arrange
bool enabled = true;
bool elevated = false;
RegistryMock* mockRegistryWrapper = new RegistryMock();
PreviewHandlerSettings previewSettings = GetPreviewHandlerSettingsObject(true, mockRegistryWrapper);
auto settings = PowerToyValues::from_json_string(GetJSONSettings(previewSettings.GetToggleSettingName(), L"false"));
previewSettings.UpdateToggleSettingState(true);
// Act
previewSettings.UpdateState(settings, enabled, elevated);
// Assert
Assert::IsFalse(previewSettings.GetToggleSettingState());
Assert::AreEqual(mockRegistryWrapper->DeleteRegistryMockProperties.NumOfCalls, 0);
Assert::AreEqual(mockRegistryWrapper->GetRegistryMockProperties.NumOfCalls, 1);
}
TEST_METHOD (UpdateState_ShouldEnableInRegistry_IfPreviewsAreEnabledAndNewSettingsStateIsTrueAndPowerToysIsElevatedAndRegistryDoesNotContainThePreview)
{
// Arrange
bool enabled = true;
bool elevated = true;
RegistryMock* mockRegistryWrapper = new RegistryMock();
PreviewHandlerSettings previewSettings = GetPreviewHandlerSettingsObject(true, mockRegistryWrapper);
auto settings = PowerToyValues::from_json_string(GetJSONSettings(previewSettings.GetToggleSettingName(), L"true")); auto settings = PowerToyValues::from_json_string(GetJSONSettings(previewSettings.GetToggleSettingName(), L"true"));
previewSettings.UpdateToggleSettingState(false); previewSettings.UpdateToggleSettingState(false);
// Act // Act
previewSettings.UpdateState(settings, enabled); previewSettings.UpdateState(settings, enabled, elevated);
// Assert // Assert
Assert::IsTrue(previewSettings.GetToggleSettingState());
Assert::AreEqual(mockRegistryWrapper->SetRegistryMockProperties.NumOfCalls, 1); Assert::AreEqual(mockRegistryWrapper->SetRegistryMockProperties.NumOfCalls, 1);
Assert::AreEqual(mockRegistryWrapper->GetRegistryMockProperties.NumOfCalls, 1);
} }
TEST_METHOD (UpdateState_ShouldOnlyUpdateToggleSettingState_IfPreviewsAreDisabled) TEST_METHOD (PreviewHandlerSettingsUpdateState_ShouldNotEnableInRegistry_IfPreviewsAreEnabledAndNewSettingsStateIsTrueAndPowerToysIsElevatedAndRegistryContainsThePreview)
{
// Arrange
bool enabled = true;
bool elevated = true;
RegistryMock* mockRegistryWrapper = new RegistryMock();
PreviewHandlerSettings previewSettings = GetPreviewHandlerSettingsObject(true, mockRegistryWrapper);
auto settings = PowerToyValues::from_json_string(GetJSONSettings(previewSettings.GetToggleSettingName(), L"true"));
previewSettings.UpdateToggleSettingState(false);
// Add expected data in registry
mockRegistryWrapper->SetMockData(previewSettings.GetRegistryValueData());
// Act
previewSettings.UpdateState(settings, enabled, elevated);
// Assert
Assert::AreEqual(mockRegistryWrapper->SetRegistryMockProperties.NumOfCalls, 0);
Assert::AreEqual(mockRegistryWrapper->GetRegistryMockProperties.NumOfCalls, 1);
}
TEST_METHOD (ThumbnailProviderSettingsUpdateState_ShouldNotEnableInRegistry_IfPreviewsAreEnabledAndNewSettingsStateIsTrueAndPowerToysIsElevatedAndRegistryContainsThePreview)
{
// Arrange
bool enabled = true;
bool elevated = true;
RegistryMock* mockRegistryWrapper = new RegistryMock();
ThumbnailProviderSettings thumbnailSettings = GetThumbnailProviderSettingsObject(true, mockRegistryWrapper);
auto settings = PowerToyValues::from_json_string(GetJSONSettings(thumbnailSettings.GetToggleSettingName(), L"true"));
thumbnailSettings.UpdateToggleSettingState(false);
// Add expected data in registry
mockRegistryWrapper->SetMockData(thumbnailSettings.GetCLSID());
// Act
thumbnailSettings.UpdateState(settings, enabled, elevated);
// Assert
Assert::AreEqual(mockRegistryWrapper->SetRegistryMockProperties.NumOfCalls, 0);
Assert::AreEqual(mockRegistryWrapper->GetRegistryMockProperties.NumOfCalls, 1);
}
TEST_METHOD (UpdateState_ShouldNotEnableInRegistry_IfPreviewsAreEnabledAndNewSettingsStateIsTrueAndPowerToysIsNotElevated)
{
// Arrange
bool enabled = true;
bool elevated = false;
RegistryMock* mockRegistryWrapper = new RegistryMock();
PreviewHandlerSettings previewSettings = GetPreviewHandlerSettingsObject(true, mockRegistryWrapper);
auto settings = PowerToyValues::from_json_string(GetJSONSettings(previewSettings.GetToggleSettingName(), L"true"));
previewSettings.UpdateToggleSettingState(false);
// Act
previewSettings.UpdateState(settings, enabled, elevated);
// Assert
Assert::AreEqual(mockRegistryWrapper->SetRegistryMockProperties.NumOfCalls, 0);
Assert::AreEqual(mockRegistryWrapper->GetRegistryMockProperties.NumOfCalls, 1);
}
TEST_METHOD (UpdateState_ShouldUpdateToggleSettingState_IfPreviewsAreEnabledAndPowerToysIsElevated)
{ {
// Arrange // Arrange
bool enabled = false; bool enabled = false;
bool elevated = true;
RegistryMock* mockRegistryWrapper = new RegistryMock(); RegistryMock* mockRegistryWrapper = new RegistryMock();
FileExplorerPreviewSettings previewSettings = GetSettingsObject(true, mockRegistryWrapper); PreviewHandlerSettings previewSettings = GetPreviewHandlerSettingsObject(true, mockRegistryWrapper);
auto settings = PowerToyValues::from_json_string(GetJSONSettings(previewSettings.GetToggleSettingName(), L"false")); auto settings = PowerToyValues::from_json_string(GetJSONSettings(previewSettings.GetToggleSettingName(), L"false"));
// Act // Act
previewSettings.UpdateState(settings, enabled); previewSettings.UpdateState(settings, enabled, elevated);
// Assert
Assert::IsFalse(previewSettings.GetToggleSettingState());
}
TEST_METHOD (UpdateState_ShouldUpdateToggleSettingState_IfPreviewsAreEnabledAndPowerToysIsNotElevated)
{
// Arrange
bool enabled = false;
bool elevated = false;
RegistryMock* mockRegistryWrapper = new RegistryMock();
PreviewHandlerSettings previewSettings = GetPreviewHandlerSettingsObject(true, mockRegistryWrapper);
auto settings = PowerToyValues::from_json_string(GetJSONSettings(previewSettings.GetToggleSettingName(), L"false"));
// Act
previewSettings.UpdateState(settings, enabled, elevated);
// Assert
Assert::IsFalse(previewSettings.GetToggleSettingState());
}
TEST_METHOD (UpdateState_ShouldOnlyUpdateToggleSettingState_IfPreviewsAreDisabledAndPowerToysIsElevated)
{
// Arrange
bool enabled = false;
bool elevated = true;
RegistryMock* mockRegistryWrapper = new RegistryMock();
PreviewHandlerSettings previewSettings = GetPreviewHandlerSettingsObject(true, mockRegistryWrapper);
auto settings = PowerToyValues::from_json_string(GetJSONSettings(previewSettings.GetToggleSettingName(), L"false"));
// Act
previewSettings.UpdateState(settings, enabled, elevated);
// Assert
Assert::IsFalse(previewSettings.GetToggleSettingState());
Assert::AreEqual(mockRegistryWrapper->SetRegistryMockProperties.NumOfCalls, 0);
Assert::AreEqual(mockRegistryWrapper->DeleteRegistryMockProperties.NumOfCalls, 0);
}
TEST_METHOD (UpdateState_ShouldOnlyUpdateToggleSettingState_IfPreviewsAreDisabledAndPowerToysIsNotElevated)
{
// Arrange
bool enabled = false;
bool elevated = false;
RegistryMock* mockRegistryWrapper = new RegistryMock();
PreviewHandlerSettings previewSettings = GetPreviewHandlerSettingsObject(true, mockRegistryWrapper);
auto settings = PowerToyValues::from_json_string(GetJSONSettings(previewSettings.GetToggleSettingName(), L"false"));
// Act
previewSettings.UpdateState(settings, enabled, elevated);
// Assert // Assert
Assert::IsFalse(previewSettings.GetToggleSettingState()); Assert::IsFalse(previewSettings.GetToggleSettingState());
@@ -148,7 +334,7 @@ namespace PreviewHandlerSettingsTest
{ {
// Arrange // Arrange
bool updatedState = false; bool updatedState = false;
FileExplorerPreviewSettings previewSettings = GetSettingsObject(true, new RegistryMock()); PreviewHandlerSettings previewSettings = GetPreviewHandlerSettingsObject(true, new RegistryMock());
// Act // Act
previewSettings.UpdateToggleSettingState(updatedState); previewSettings.UpdateToggleSettingState(updatedState);
@@ -157,41 +343,75 @@ namespace PreviewHandlerSettingsTest
Assert::AreEqual(previewSettings.GetToggleSettingState(), updatedState); Assert::AreEqual(previewSettings.GetToggleSettingState(), updatedState);
} }
TEST_METHOD(EnablePreview_ShouldCallSetRegistryValueWithValidArguments_WhenCalled) TEST_METHOD (PreviewHandlerSettingsEnable_ShouldCallSetRegistryValueWithValidArguments_WhenCalled)
{ {
// Arrange // Arrange
RegistryMock* mockRegistryWrapper = new RegistryMock(); RegistryMock* mockRegistryWrapper = new RegistryMock();
FileExplorerPreviewSettings previewSettings = GetSettingsObject(true, mockRegistryWrapper); PreviewHandlerSettings previewSettings = GetPreviewHandlerSettingsObject(true, mockRegistryWrapper);
// Act // Act
previewSettings.EnablePreview(); previewSettings.Enable();
// Assert // Assert
Assert::AreEqual(mockRegistryWrapper->SetRegistryMockProperties.NumOfCalls, 1); Assert::AreEqual(mockRegistryWrapper->SetRegistryMockProperties.NumOfCalls, 1);
Assert::AreEqual(mockRegistryWrapper->SetRegistryMockProperties.SubKey, preview_handlers_subkey); Assert::AreEqual(mockRegistryWrapper->SetRegistryMockProperties.SubKey, PreviewHandlerSettings::GetSubkey());
Assert::AreEqual(mockRegistryWrapper->SetRegistryMockProperties.ValueName, previewSettings.GetCLSID()); Assert::AreEqual(mockRegistryWrapper->SetRegistryMockProperties.ValueName, previewSettings.GetCLSID());
Assert::AreEqual((ULONG_PTR)(mockRegistryWrapper->SetRegistryMockProperties.Scope), (ULONG_PTR)(HKEY_CURRENT_USER)); Assert::AreEqual(mockRegistryWrapper->SetRegistryMockProperties.ValueData, previewSettings.GetRegistryValueData().c_str());
Assert::AreEqual((ULONG_PTR)(mockRegistryWrapper->SetRegistryMockProperties.Scope), (ULONG_PTR)(HKEY_LOCAL_MACHINE));
} }
TEST_METHOD(DisablePreview_ShouldCallDeleteRegistryValueWithValidArguments_WhenCalled) TEST_METHOD (PreviewHandlerDisable_ShouldCallDeleteRegistryValueWithValidArguments_WhenCalled)
{ {
// Arrange // Arrange
RegistryMock* mockRegistryWrapper = new RegistryMock(); RegistryMock* mockRegistryWrapper = new RegistryMock();
FileExplorerPreviewSettings previewSettings = GetSettingsObject(true, mockRegistryWrapper); PreviewHandlerSettings previewSettings = GetPreviewHandlerSettingsObject(true, mockRegistryWrapper);
// Act // Act
previewSettings.DisablePreview(); previewSettings.Disable();
// Assert // Assert
Assert::AreEqual(mockRegistryWrapper->DeleteRegistryMockProperties.NumOfCalls, 1); Assert::AreEqual(mockRegistryWrapper->DeleteRegistryMockProperties.NumOfCalls, 1);
Assert::AreEqual(mockRegistryWrapper->DeleteRegistryMockProperties.SubKey, preview_handlers_subkey); Assert::AreEqual(mockRegistryWrapper->DeleteRegistryMockProperties.SubKey, PreviewHandlerSettings::GetSubkey());
Assert::AreEqual(mockRegistryWrapper->DeleteRegistryMockProperties.ValueName, previewSettings.GetCLSID()); Assert::AreEqual(mockRegistryWrapper->DeleteRegistryMockProperties.ValueName, previewSettings.GetCLSID());
Assert::AreEqual((ULONG_PTR)(mockRegistryWrapper->DeleteRegistryMockProperties.Scope), (ULONG_PTR)(HKEY_CURRENT_USER)); Assert::AreEqual((ULONG_PTR)(mockRegistryWrapper->DeleteRegistryMockProperties.Scope), (ULONG_PTR)(HKEY_LOCAL_MACHINE));
} }
FileExplorerPreviewSettings GetSettingsObject(bool defaultState, RegistryWrapperIface* registryMock) TEST_METHOD (ThumbnailProviderSettingsEnable_ShouldCallSetRegistryValueWithValidArguments_WhenCalled)
{ {
return FileExplorerPreviewSettings( // Arrange
RegistryMock* mockRegistryWrapper = new RegistryMock();
ThumbnailProviderSettings thumbnailSettings = GetThumbnailProviderSettingsObject(true, mockRegistryWrapper);
// Act
thumbnailSettings.Enable();
// Assert
Assert::AreEqual(mockRegistryWrapper->SetRegistryMockProperties.NumOfCalls, 1);
Assert::AreEqual(mockRegistryWrapper->SetRegistryMockProperties.SubKey, thumbnailSettings.GetSubkey());
Assert::AreEqual(mockRegistryWrapper->SetRegistryMockProperties.ValueName, nullptr);
Assert::AreEqual(mockRegistryWrapper->SetRegistryMockProperties.ValueData, thumbnailSettings.GetCLSID());
Assert::AreEqual((ULONG_PTR)(mockRegistryWrapper->SetRegistryMockProperties.Scope), (ULONG_PTR)(HKEY_CLASSES_ROOT));
}
TEST_METHOD (ThumbnailProviderSettingsDisable_ShouldCallDeleteRegistryValueWithValidArguments_WhenCalled)
{
// Arrange
RegistryMock* mockRegistryWrapper = new RegistryMock();
ThumbnailProviderSettings thumbnailSettings = GetThumbnailProviderSettingsObject(true, mockRegistryWrapper);
// Act
thumbnailSettings.Disable();
// Assert
Assert::AreEqual(mockRegistryWrapper->DeleteRegistryMockProperties.NumOfCalls, 1);
Assert::AreEqual(mockRegistryWrapper->DeleteRegistryMockProperties.SubKey, thumbnailSettings.GetSubkey());
Assert::AreEqual(mockRegistryWrapper->DeleteRegistryMockProperties.ValueName, nullptr);
Assert::AreEqual((ULONG_PTR)(mockRegistryWrapper->DeleteRegistryMockProperties.Scope), (ULONG_PTR)(HKEY_CLASSES_ROOT));
}
PreviewHandlerSettings GetPreviewHandlerSettingsObject(bool defaultState, RegistryWrapperIface* registryMock)
{
return PreviewHandlerSettings(
defaultState, defaultState,
L"valid-name", L"valid-name",
L"valid-description", L"valid-description",
@@ -200,7 +420,19 @@ namespace PreviewHandlerSettingsTest
registryMock); registryMock);
} }
std::wstring GetJSONSettings(const std::wstring &_settingsNameId, const std::wstring &_value) const ThumbnailProviderSettings GetThumbnailProviderSettingsObject(bool defaultState, RegistryWrapperIface* registryMock)
{
return ThumbnailProviderSettings(
defaultState,
L"valid-name",
L"valid-description",
L"valid-guid",
L"valid-handler",
registryMock,
L"valid-subkey");
}
std::wstring GetJSONSettings(const std::wstring& _settingsNameId, const std::wstring& _value) const
{ {
return L"{\"name\":\"Module Name\",\"properties\" : {\"" + _settingsNameId + L"\":{\"value\":" + _value + L"}},\"version\" : \"1.0\" }"; return L"{\"name\":\"Module Name\",\"properties\" : {\"" + _settingsNameId + L"\":{\"value\":" + _value + L"}},\"version\" : \"1.0\" }";
} }