diff --git a/.pipelines/pipeline.user.windows.yml b/.pipelines/pipeline.user.windows.yml index 636c090b2a..1c6d883455 100644 --- a/.pipelines/pipeline.user.windows.yml +++ b/.pipelines/pipeline.user.windows.yml @@ -42,8 +42,6 @@ restore: name: 'Restore Tools packages' command: '.pipelines\restore-tools.cmd' - - build: commands: # Localize the files before the Build PowerToys step to generate translated resx files from the lcl files @@ -113,6 +111,8 @@ build: - 'modules\FileExplorerPreview\MarkdownPreviewHandler.comhost.dll' - 'modules\FileExplorerPreview\PdfPreviewHandler.dll' - 'modules\FileExplorerPreview\PdfPreviewHandler.comhost.dll' + - 'modules\FileExplorerPreview\PdfThumbnailProvider.dll' + - 'modules\FileExplorerPreview\PdfThumbnailProvider.comhost.dll' - 'modules\FileExplorerPreview\powerpreview.dll' - 'modules\FileExplorerPreview\PreviewHandlerCommon.dll' - 'modules\FileExplorerPreview\SvgPreviewHandler.dll' @@ -229,7 +229,6 @@ build: signing_options: sign_inline: true # This does signing as soon as this command completes - #package: # commands: # - !!buildcommand diff --git a/PowerToys.sln b/PowerToys.sln index d58e52fadd..b17039b9fd 100644 --- a/PowerToys.sln +++ b/PowerToys.sln @@ -17,6 +17,7 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "runner", "src\runner\runner {0B593A6C-4143-4337-860E-DB5710FB87DB} = {0B593A6C-4143-4337-860E-DB5710FB87DB} {E364F67B-BB12-4E91-B639-355866EBCD8B} = {E364F67B-BB12-4E91-B639-355866EBCD8B} {D940E07F-532C-4FF3-883F-790DA014F19A} = {D940E07F-532C-4FF3-883F-790DA014F19A} + {69E1EE8D-143A-4060-9129-4658ACF14AAF} = {69E1EE8D-143A-4060-9129-4658ACF14AAF} {DA425894-6E13-404F-8DCB-78584EC0557A} = {DA425894-6E13-404F-8DCB-78584EC0557A} {2BE46397-4DFA-414C-9BD4-41E4BBF8CB34} = {2BE46397-4DFA-414C-9BD4-41E4BBF8CB34} {A7D5099E-F0FD-4BF3-8522-5A682759F915} = {A7D5099E-F0FD-4BF3-8522-5A682759F915} @@ -362,6 +363,10 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "VideoConferenceProxyFilter" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "VideoConference", "VideoConference", "{470FBAF9-E1F8-4F3E-8786-198A1C81C8A8}" EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PdfThumbnailProvider", "src\modules\previewpane\PdfThumbnailProvider\PdfThumbnailProvider.csproj", "{11491FD8-F921-48BF-880C-7FEA185B80A1}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "UnitTests-PdfThumbnailProvider", "src\modules\previewpane\UnitTests-PdfThumbnailProvider\UnitTests-PdfThumbnailProvider.csproj", "{F40C3397-1834-4530-B2D9-8F8B8456BCDF}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|x64 = Debug|x64 @@ -948,6 +953,18 @@ Global {AC2857B4-103D-4D6D-9740-926EBF785042}.Release|x64.Build.0 = Release|x64 {AC2857B4-103D-4D6D-9740-926EBF785042}.Release|x86.ActiveCfg = Release|Win32 {AC2857B4-103D-4D6D-9740-926EBF785042}.Release|x86.Build.0 = Release|Win32 + {11491FD8-F921-48BF-880C-7FEA185B80A1}.Debug|x64.ActiveCfg = Debug|x64 + {11491FD8-F921-48BF-880C-7FEA185B80A1}.Debug|x64.Build.0 = Debug|x64 + {11491FD8-F921-48BF-880C-7FEA185B80A1}.Debug|x86.ActiveCfg = Debug|x64 + {11491FD8-F921-48BF-880C-7FEA185B80A1}.Release|x64.ActiveCfg = Release|x64 + {11491FD8-F921-48BF-880C-7FEA185B80A1}.Release|x64.Build.0 = Release|x64 + {11491FD8-F921-48BF-880C-7FEA185B80A1}.Release|x86.ActiveCfg = Release|x64 + {F40C3397-1834-4530-B2D9-8F8B8456BCDF}.Debug|x64.ActiveCfg = Debug|x64 + {F40C3397-1834-4530-B2D9-8F8B8456BCDF}.Debug|x64.Build.0 = Debug|x64 + {F40C3397-1834-4530-B2D9-8F8B8456BCDF}.Debug|x86.ActiveCfg = Debug|x64 + {F40C3397-1834-4530-B2D9-8F8B8456BCDF}.Release|x64.ActiveCfg = Release|x64 + {F40C3397-1834-4530-B2D9-8F8B8456BCDF}.Release|x64.Build.0 = Release|x64 + {F40C3397-1834-4530-B2D9-8F8B8456BCDF}.Release|x86.ActiveCfg = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -1061,6 +1078,8 @@ Global {5ABA70DE-3A3F-41F6-A1F5-D1F74F54F9BB} = {470FBAF9-E1F8-4F3E-8786-198A1C81C8A8} {AC2857B4-103D-4D6D-9740-926EBF785042} = {470FBAF9-E1F8-4F3E-8786-198A1C81C8A8} {470FBAF9-E1F8-4F3E-8786-198A1C81C8A8} = {4574FDD0-F61D-4376-98BF-E5A1262C11EC} + {11491FD8-F921-48BF-880C-7FEA185B80A1} = {2F305555-C296-497E-AC20-5FA1B237996A} + {F40C3397-1834-4530-B2D9-8F8B8456BCDF} = {2F305555-C296-497E-AC20-5FA1B237996A} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {C3A2F9D1-7930-4EF4-A6FC-7EE0A99821D0} diff --git a/installer/PowerToysSetup/Product.wxs b/installer/PowerToysSetup/Product.wxs index 164a248b19..3790b05b13 100644 --- a/installer/PowerToysSetup/Product.wxs +++ b/installer/PowerToysSetup/Product.wxs @@ -511,6 +511,19 @@ + + + + + + + + + + + + + @@ -543,6 +556,10 @@ + + + + @@ -791,7 +808,7 @@ - + @@ -809,6 +826,11 @@ + + + + + diff --git a/src/modules/previewpane/PdfPreviewHandler/PdfPreviewHandler.csproj b/src/modules/previewpane/PdfPreviewHandler/PdfPreviewHandler.csproj index a49bb3b7b3..b6e6a59aa4 100644 --- a/src/modules/previewpane/PdfPreviewHandler/PdfPreviewHandler.csproj +++ b/src/modules/previewpane/PdfPreviewHandler/PdfPreviewHandler.csproj @@ -65,7 +65,7 @@ - $(MSBuildProgramFiles32)\Windows Kits\10\UnionMetadata\10.0.17134.0\Windows.winmd + $(MSBuildProgramFiles32)\Windows Kits\10\UnionMetadata\10.0.18362.0\Windows.winmd true diff --git a/src/modules/previewpane/PdfThumbnailProvider/PdfThumbnailProvider.cs b/src/modules/previewpane/PdfThumbnailProvider/PdfThumbnailProvider.cs new file mode 100644 index 0000000000..c12152e673 --- /dev/null +++ b/src/modules/previewpane/PdfThumbnailProvider/PdfThumbnailProvider.cs @@ -0,0 +1,96 @@ +// Copyright (c) Microsoft Corporation +// The Microsoft Corporation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. +using System; +using System.Drawing; +using System.IO; +using System.Runtime.InteropServices; +using System.Runtime.InteropServices.ComTypes; +using Common.ComInterlop; +using Common.Utilities; +using Windows.Data.Pdf; +using Windows.Storage.Streams; + +namespace Microsoft.PowerToys.ThumbnailHandler.Pdf +{ + /// + /// PDF Thumbnail Provider. + /// + [Guid("BCC13D15-9720-4CC4-8371-EA74A274741E")] + [ClassInterface(ClassInterfaceType.None)] + [ComVisible(true)] + public class PdfThumbnailProvider : IInitializeWithStream, IThumbnailProvider + { + /// + /// Gets the stream object to access file. + /// + public IStream Stream { get; private set; } + + /// + /// The maximum dimension (width or height) thumbnail we will generate. + /// + private const uint MaxThumbnailSize = 10000; + + /// + public void Initialize(IStream pstream, uint grfMode) + { + // Ignore the grfMode always use read mode to access the file. + this.Stream = pstream; + } + + /// + public void GetThumbnail(uint cx, out IntPtr phbmp, out WTS_ALPHATYPE pdwAlpha) + { + phbmp = IntPtr.Zero; + pdwAlpha = WTS_ALPHATYPE.WTSAT_UNKNOWN; + + if (cx == 0 || cx > MaxThumbnailSize) + { + return; + } + + using var dataStream = new ReadonlyStream(this.Stream as IStream); + using var memStream = new MemoryStream(); + + dataStream.CopyTo(memStream); + memStream.Position = 0; + + // AsRandomAccessStream() extension method from System.Runtime.WindowsRuntime + var pdf = PdfDocument.LoadFromStreamAsync(memStream.AsRandomAccessStream()).GetAwaiter().GetResult(); + + if (pdf.PageCount > 0) + { + using var page = pdf.GetPage(0); + + var image = PageToImage(page, cx); + + using Bitmap thumbnail = new Bitmap(image); + + phbmp = thumbnail.GetHbitmap(); + pdwAlpha = WTS_ALPHATYPE.WTSAT_RGB; + } + } + + /// + /// Transform the PdfPage to an Image. + /// + /// The page to transform to an Image. + /// The height of the page. + /// An object of type + private static Image PageToImage(PdfPage page, uint height) + { + Image imageOfPage; + + using var stream = new InMemoryRandomAccessStream(); + + page.RenderToStreamAsync(stream, new PdfPageRenderOptions() + { + DestinationHeight = height, + }).GetAwaiter().GetResult(); + + imageOfPage = Image.FromStream(stream.AsStream()); + + return imageOfPage; + } + } +} diff --git a/src/modules/previewpane/PdfThumbnailProvider/PdfThumbnailProvider.csproj b/src/modules/previewpane/PdfThumbnailProvider/PdfThumbnailProvider.csproj new file mode 100644 index 0000000000..dd026f4b54 --- /dev/null +++ b/src/modules/previewpane/PdfThumbnailProvider/PdfThumbnailProvider.csproj @@ -0,0 +1,71 @@ + + + x64 + true + {11491FD8-F921-48BF-880C-7FEA185B80A1} + Microsoft.PowerToys.ThumbnailHandler.Pdf + PdfThumbnailProvider + PdfThumbnailProvider + PowerToys PdfPreviewHandler + Microsoft Corporation + Copyright (C) 2020 Microsoft Corporation + PowerToys + netcoreapp3.1 + true + true + Microsoft Corporation + PowerToys + en-US + PowerToys PdfPreviewHandler + Copyright (C) 2020 Microsoft Corporation + $(SolutionDir)$(Platform)\$(Configuration)\modules\FileExplorerPreview\ + true + false + false + true + + + + + + + all + + + all + + + all + + + all + + + all + + + all + + + + + + + + + + + + + StyleCop.json + + + + + + $(MSBuildProgramFiles32)\Windows Kits\10\UnionMetadata\10.0.18362.0\Windows.winmd + true + + + + \ No newline at end of file diff --git a/src/modules/previewpane/SvgThumbnailProvider/SvgThumbnailProvider.cs b/src/modules/previewpane/SvgThumbnailProvider/SvgThumbnailProvider.cs index 73810bbc60..a3c9ff4005 100644 --- a/src/modules/previewpane/SvgThumbnailProvider/SvgThumbnailProvider.cs +++ b/src/modules/previewpane/SvgThumbnailProvider/SvgThumbnailProvider.cs @@ -12,7 +12,6 @@ using System.Runtime.InteropServices.ComTypes; using System.Windows.Forms; using Common.ComInterlop; using Common.Utilities; -using Microsoft.PowerToys.Telemetry; using PreviewHandlerCommon; namespace Microsoft.PowerToys.ThumbnailHandler.Svg diff --git a/src/modules/previewpane/UnitTests-PdfThumbnailProvider/HelperFiles/sample.pdf b/src/modules/previewpane/UnitTests-PdfThumbnailProvider/HelperFiles/sample.pdf new file mode 100644 index 0000000000..96304d9b21 Binary files /dev/null and b/src/modules/previewpane/UnitTests-PdfThumbnailProvider/HelperFiles/sample.pdf differ diff --git a/src/modules/previewpane/UnitTests-PdfThumbnailProvider/PdfThumbnailProviderTests.cs b/src/modules/previewpane/UnitTests-PdfThumbnailProvider/PdfThumbnailProviderTests.cs new file mode 100644 index 0000000000..482aa94dcd --- /dev/null +++ b/src/modules/previewpane/UnitTests-PdfThumbnailProvider/PdfThumbnailProviderTests.cs @@ -0,0 +1,93 @@ +// Copyright (c) Microsoft Corporation +// The Microsoft Corporation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Drawing; +using System.IO; +using System.Runtime.InteropServices; +using System.Runtime.InteropServices.ComTypes; +using System.Text; +using Common.ComInterlop; +using Microsoft.PowerToys.STATestExtension; +using Microsoft.PowerToys.ThumbnailHandler.Pdf; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Moq; + +namespace PdfThumbnailProviderUnitTests +{ + [STATestClass] + public class PdfThumbnailProviderTests + { + [TestMethod] + public void GetThumbnailValidStreamPDF() + { + // Act + var file = File.ReadAllBytes("HelperFiles/sample.pdf"); + + PdfThumbnailProvider provider = new PdfThumbnailProvider(); + + provider.Initialize(GetMockStream(file), 0); + + provider.GetThumbnail(256, out IntPtr bitmap, out WTS_ALPHATYPE alphaType); + + Assert.IsTrue(bitmap != IntPtr.Zero); + Assert.IsTrue(alphaType == WTS_ALPHATYPE.WTSAT_RGB); + } + + [TestMethod] + public void GetThumbnailInValidSizePDF() + { + // Act + var file = File.ReadAllBytes("HelperFiles/sample.pdf"); + + PdfThumbnailProvider provider = new PdfThumbnailProvider(); + + provider.Initialize(GetMockStream(file), 0); + + provider.GetThumbnail(0, out IntPtr bitmap, out WTS_ALPHATYPE alphaType); + + Assert.IsTrue(bitmap == IntPtr.Zero); + Assert.IsTrue(alphaType == WTS_ALPHATYPE.WTSAT_UNKNOWN); + } + + [TestMethod] + public void GetThumbnailToBigPDF() + { + // Act + var file = File.ReadAllBytes("HelperFiles/sample.pdf"); + + PdfThumbnailProvider provider = new PdfThumbnailProvider(); + + provider.Initialize(GetMockStream(file), 0); + + provider.GetThumbnail(10001, out IntPtr bitmap, out WTS_ALPHATYPE alphaType); + + Assert.IsTrue(bitmap == IntPtr.Zero); + Assert.IsTrue(alphaType == WTS_ALPHATYPE.WTSAT_UNKNOWN); + } + + private static IStream GetMockStream(byte[] sourceArray) + { + var streamMock = new Mock(); + var firstCall = true; + streamMock + .Setup(x => x.Read(It.IsAny(), It.IsAny(), It.IsAny())) + .Callback((buffer, countToRead, bytesReadPtr) => + { + if (firstCall) + { + Array.Copy(sourceArray, 0, buffer, 0, sourceArray.Length); + Marshal.WriteInt32(bytesReadPtr, sourceArray.Length); + firstCall = false; + } + else + { + Marshal.WriteInt32(bytesReadPtr, 0); + } + }); + + return streamMock.Object; + } + } +} diff --git a/src/modules/previewpane/UnitTests-PdfThumbnailProvider/UnitTests-PdfThumbnailProvider.csproj b/src/modules/previewpane/UnitTests-PdfThumbnailProvider/UnitTests-PdfThumbnailProvider.csproj new file mode 100644 index 0000000000..c6360e675a --- /dev/null +++ b/src/modules/previewpane/UnitTests-PdfThumbnailProvider/UnitTests-PdfThumbnailProvider.csproj @@ -0,0 +1,78 @@ + + + x64 + UnitTests-PdfThumbnailProvider + PowerToys UnitTests-PdfThumbnailProvider + Microsoft Corporation + Copyright (C) 2021 Microsoft Corporation + PowerToys + UnitTests-PdfThumbnailProvider + Microsoft Corporation + PowerToys + en-US + PowerToys UnitTests-PdfThumbnailProvider + Copyright (C) 2021 Microsoft Corporation + + + + {F40C3397-1834-4530-B2D9-8F8B8456BCDF} + PdfThumbnailProviderUnitTests + netcoreapp3.1 + {3AC096D0-A1C2-E12C-1390-A8335801FDAB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} + $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) + $(ProgramFiles)\Common Files\microsoft shared\VSTT\$(VisualStudioVersion)\UITestExtensionPackages + False + UnitTest + + + + + + + + + + + + all + + + all + + + all + + + all + + + all + + + + + + all + + + + + + + + + + + + + + + StyleCop.json + + + + + Always + + + \ No newline at end of file diff --git a/src/modules/previewpane/UnitTests-PdfThumbnailProvider/app.config b/src/modules/previewpane/UnitTests-PdfThumbnailProvider/app.config new file mode 100644 index 0000000000..74312e4551 --- /dev/null +++ b/src/modules/previewpane/UnitTests-PdfThumbnailProvider/app.config @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/modules/previewpane/powerpreview/CLSID.h b/src/modules/previewpane/powerpreview/CLSID.h index 104e2d8ef8..ce6e5bc5dc 100644 --- a/src/modules/previewpane/powerpreview/CLSID.h +++ b/src/modules/previewpane/powerpreview/CLSID.h @@ -28,6 +28,9 @@ const CLSID CLSID_SHIMActivateSvgThumbnailProvider = { 0x9C723B8C, 0x4F5C, 0x414 // 36B27788-A8BB-4698-A756-DF9F11F64F84 const CLSID CLSID_SvgThumbnailProvider = { 0x36B27788, 0xA8BB, 0x4698, { 0xA7, 0x56, 0xDF, 0x9F, 0x11, 0xF6, 0x4F, 0x84 } }; +// BCC13D15-9720-4CC4-8371-EA74A274741E +const GUID CLSID_PdfThumbnailProvider = { 0xbcc13d15, 0x9720, 0x4cc4, { 0x83, 0x71, 0xea, 0x74, 0xa2, 0x74, 0x74, 0x1e } }; + // Pairs of NativeClsid vs ManagedClsid used for preview handlers. const std::vector> NativeToManagedClsid({ { CLSID_SHIMActivateMdPreviewHandler, CLSID_MdPreviewHandler }, diff --git a/src/modules/previewpane/powerpreview/Resources.resx b/src/modules/previewpane/powerpreview/Resources.resx index 7af9b5effe..203a0bfc3f 100644 --- a/src/modules/previewpane/powerpreview/Resources.resx +++ b/src/modules/previewpane/powerpreview/Resources.resx @@ -174,4 +174,7 @@ PDF Previewer + + Pdf Thumbnail Provider + \ No newline at end of file diff --git a/src/modules/previewpane/powerpreview/powerpreview.cpp b/src/modules/previewpane/powerpreview/powerpreview.cpp index 27e6a482f6..8bec06e0a3 100644 --- a/src/modules/previewpane/powerpreview/powerpreview.cpp +++ b/src/modules/previewpane/powerpreview/powerpreview.cpp @@ -50,6 +50,16 @@ PowerPreviewModule::PowerPreviewModule() : std::make_unique(), L".svg\\shellex\\{E357FCCD-A995-4576-B01F-234630154E96}")); + // PDF + m_fileExplorerModules.emplace_back(std::make_unique( + true, + L"pdf-thumbnail-toggle-setting", + GET_RESOURCE_STRING(IDS_PDF_THUMBNAIL_PROVIDER_SETTINGS_DESCRIPTION), + L"{BCC13D15-9720-4CC4-8371-EA74A274741E}", + L"Pdf Thumbnail Provider", + std::make_unique(), + L".pdf\\shellex\\{E357FCCD-A995-4576-B01F-234630154E96}")); + // Initialize the toggle states for each module. init_settings(); diff --git a/src/settings-ui/Microsoft.PowerToys.Settings.UI.Library/PowerPreviewProperties.cs b/src/settings-ui/Microsoft.PowerToys.Settings.UI.Library/PowerPreviewProperties.cs index 8a5b5f7c83..a1607b2c86 100644 --- a/src/settings-ui/Microsoft.PowerToys.Settings.UI.Library/PowerPreviewProperties.cs +++ b/src/settings-ui/Microsoft.PowerToys.Settings.UI.Library/PowerPreviewProperties.cs @@ -80,6 +80,23 @@ namespace Microsoft.PowerToys.Settings.UI.Library } } + private bool enablePdfThumbnail = true; + + [JsonPropertyName("pdf-thumbnail-toggle-setting")] + [JsonConverter(typeof(BoolPropertyJsonConverter))] + public bool EnablePdfThumbnail + { + get => enablePdfThumbnail; + set + { + if (value != enablePdfThumbnail) + { + LogTelemetryEvent(value); + enablePdfThumbnail = value; + } + } + } + public PowerPreviewProperties() { } diff --git a/src/settings-ui/Microsoft.PowerToys.Settings.UI.Library/ViewModels/PowerPreviewViewModel.cs b/src/settings-ui/Microsoft.PowerToys.Settings.UI.Library/ViewModels/PowerPreviewViewModel.cs index ea1f22ea2a..71d7112cdb 100644 --- a/src/settings-ui/Microsoft.PowerToys.Settings.UI.Library/ViewModels/PowerPreviewViewModel.cs +++ b/src/settings-ui/Microsoft.PowerToys.Settings.UI.Library/ViewModels/PowerPreviewViewModel.cs @@ -50,12 +50,14 @@ namespace Microsoft.PowerToys.Settings.UI.Library.ViewModels _svgThumbnailIsEnabled = Settings.Properties.EnableSvgThumbnail; _mdRenderIsEnabled = Settings.Properties.EnableMdPreview; _pdfRenderIsEnabled = Settings.Properties.EnablePdfPreview; + _pdfThumbnailIsEnabled = Settings.Properties.EnablePdfThumbnail; } private bool _svgRenderIsEnabled; private bool _mdRenderIsEnabled; private bool _pdfRenderIsEnabled; private bool _svgThumbnailIsEnabled; + private bool _pdfThumbnailIsEnabled; public bool SVGRenderIsEnabled { @@ -129,6 +131,24 @@ namespace Microsoft.PowerToys.Settings.UI.Library.ViewModels } } + public bool PDFThumbnailIsEnabled + { + get + { + return _pdfThumbnailIsEnabled; + } + + set + { + if (value != _pdfThumbnailIsEnabled) + { + _pdfThumbnailIsEnabled = value; + Settings.Properties.EnablePdfThumbnail = value; + RaisePropertyChanged(); + } + } + } + public string GetSettingsSubPath() { return _settingsConfigFileFolder + "\\" + ModuleName; diff --git a/src/settings-ui/Microsoft.PowerToys.Settings.UI.UnitTests/ViewModelTests/PowerPreview.cs b/src/settings-ui/Microsoft.PowerToys.Settings.UI.UnitTests/ViewModelTests/PowerPreview.cs index 878069c8a9..7fc7cba302 100644 --- a/src/settings-ui/Microsoft.PowerToys.Settings.UI.UnitTests/ViewModelTests/PowerPreview.cs +++ b/src/settings-ui/Microsoft.PowerToys.Settings.UI.UnitTests/ViewModelTests/PowerPreview.cs @@ -60,6 +60,7 @@ namespace ViewModelTests Assert.AreEqual(originalSettings.Properties.EnablePdfPreview, viewModel.PDFRenderIsEnabled); Assert.AreEqual(originalSettings.Properties.EnableSvgPreview, viewModel.SVGRenderIsEnabled); Assert.AreEqual(originalSettings.Properties.EnableSvgThumbnail, viewModel.SVGThumbnailIsEnabled); + Assert.AreEqual(originalSettings.Properties.EnablePdfThumbnail, viewModel.PDFThumbnailIsEnabled); // Verify that the stub file was used var expectedCallCount = 2; // once via the view model, and once by the test (GetSettings) @@ -102,6 +103,24 @@ namespace ViewModelTests viewModel.SVGThumbnailIsEnabled = true; } + [TestMethod] + public void PDFThumbnailIsEnabledShouldPrevHandlerWhenSuccessful() + { + // Assert + Func sendMockIPCConfigMSG = msg => + { + SndModuleSettings snd = JsonSerializer.Deserialize>(msg); + Assert.IsTrue(snd.PowertoysSetting.FileExplorerPreviewSettings.Properties.EnablePdfThumbnail); + return 0; + }; + + // arrange + PowerPreviewViewModel viewModel = new PowerPreviewViewModel(SettingsRepository.GetInstance(mockPowerPreviewSettingsUtils.Object), SettingsRepository.GetInstance(mockGeneralSettingsUtils.Object), sendMockIPCConfigMSG, PowerPreviewSettings.ModuleName); + + // act + viewModel.PDFThumbnailIsEnabled = true; + } + [TestMethod] public void MDRenderIsEnabledShouldPrevHandlerWhenSuccessful() { diff --git a/src/settings-ui/Microsoft.PowerToys.Settings.UI/Strings/en-us/Resources.resw b/src/settings-ui/Microsoft.PowerToys.Settings.UI/Strings/en-us/Resources.resw index d51f5eba1a..09e1f3aba8 100644 --- a/src/settings-ui/Microsoft.PowerToys.Settings.UI/Strings/en-us/Resources.resw +++ b/src/settings-ui/Microsoft.PowerToys.Settings.UI/Strings/en-us/Resources.resw @@ -586,6 +586,10 @@ Enable SVG (.svg) thumbnails Do you want this feature on / off + + Enable PDF (.pdf) thumbnails + Do you want this feature on / off + These settings allow you to manage your Windows File Explorer custom preview handlers. @@ -1194,7 +1198,7 @@ Made with 💗 by Microsoft and the PowerToys community. FancyZones is a window manager that makes it easy to create complex window layouts and quickly position windows into those layouts. - PowerToys introduces add-ons to the Window’s File Explorer that will currently enable Markdown files (.md) and SVG icons (.svg) to be viewed in the preview pane. + PowerToys introduces add-ons to the Window’s File Explorer that will currently enable Markdown files (.md), PDF files (.pdf) and SVG icons (.svg) to be viewed in the preview pane. Image Resizer is a Windows shell extension for simple bulk image-resizing. @@ -1245,7 +1249,7 @@ Take a moment to preview the various utilities listed or view our comprehensive Open File Explorer, **select the View tab** in the File Explorer ribbon, then **select Preview Pane**. -From there, simply click on a Markdown file or SVG icon in the File Explorer and observe the content on the preview pane! +From there, simply click on a Markdown file, PDF file or SVG icon in the File Explorer and observe the content on the preview pane! How to create mappings diff --git a/src/settings-ui/Microsoft.PowerToys.Settings.UI/Views/PowerPreviewPage.xaml b/src/settings-ui/Microsoft.PowerToys.Settings.UI/Views/PowerPreviewPage.xaml index 5693f88554..04e7411a5b 100644 --- a/src/settings-ui/Microsoft.PowerToys.Settings.UI/Views/PowerPreviewPage.xaml +++ b/src/settings-ui/Microsoft.PowerToys.Settings.UI/Views/PowerPreviewPage.xaml @@ -67,6 +67,13 @@ IsEnabled="{Binding Mode=OneWay, Path=IsElevated}"/> + + + + + + diff --git a/tools/BugReportTool/BugReportTool/RegistryUtils.cpp b/tools/BugReportTool/BugReportTool/RegistryUtils.cpp index 6acad09576..b205bb0ab4 100644 --- a/tools/BugReportTool/BugReportTool/RegistryUtils.cpp +++ b/tools/BugReportTool/BugReportTool/RegistryUtils.cpp @@ -13,6 +13,8 @@ namespace { HKEY_CLASSES_ROOT, L"CLSID\\{36B27788-A8BB-4698-A756-DF9F11F64F84}" }, { HKEY_CLASSES_ROOT, L"CLSID\\{45769bcc-e8fd-42d0-947e-02beef77a1f5}" }, { HKEY_CLASSES_ROOT, L"AppID\\{CF142243-F059-45AF-8842-DBBE9783DB14}" }, + { HKEY_CLASSES_ROOT, L"CLSID\\{07665729-6243-4746-95b7-79579308d1b2}" }, + { HKEY_CLASSES_ROOT, L"CLSID\\{BCC13D15-9720-4CC4-8371-EA74A274741E}" }, { HKEY_CLASSES_ROOT, L"CLSID\\{51B4D7E5-7568-4234-B4BB-47FB3C016A69}\\InprocServer32" }, { HKEY_CLASSES_ROOT, L"CLSID\\{0440049F-D1DC-4E46-B27B-98393D79486B}" }, { HKEY_CLASSES_ROOT, L"AllFileSystemObjects\\ShellEx\\ContextMenuHandlers\\PowerRenameExt" }, @@ -20,7 +22,8 @@ namespace { HKEY_CLASSES_ROOT, L".svg\\shellex\\{8895b1c6-b41f-4c1c-a562-0d564250836f}" }, { HKEY_CLASSES_ROOT, L".svg\\shellex\\{E357FCCD-A995-4576-B01F-234630154E96}" }, { HKEY_CLASSES_ROOT, L".md\\shellex\\{8895b1c6-b41f-4c1c-a562-0d564250836f}" }, - { HKEY_CLASSES_ROOT, L".pdf\\shellex\\{8895b1c6-b41f-4c1c-a562-0d564250836f}" } + { HKEY_CLASSES_ROOT, L".pdf\\shellex\\{8895b1c6-b41f-4c1c-a562-0d564250836f}" }, + { HKEY_CLASSES_ROOT, L".pdf\\shellex\\{E357FCCD-A995-4576-B01F-234630154E96}" } }; vector> registryValues = {