diff --git a/.github/actions/spell-check/allow/names.txt b/.github/actions/spell-check/allow/names.txt index d2772b39b4..c18cf24f09 100644 --- a/.github/actions/spell-check/allow/names.txt +++ b/.github/actions/spell-check/allow/names.txt @@ -46,6 +46,7 @@ chrdavis Chrzan clayton Coplen +craigloewen crutkas damienleroy davidegiacometti @@ -87,6 +88,7 @@ martinchrzan martinmoene Melman Mikhayelyan +msft Myrvold Nemeth nielslaute diff --git a/.github/workflows/similarIssues.yml b/.github/workflows/similarIssues.yml new file mode 100644 index 0000000000..418e152348 --- /dev/null +++ b/.github/workflows/similarIssues.yml @@ -0,0 +1,33 @@ +name: GitGudSimilarIssues comments + +on: + issues: + types: [opened] + +jobs: + getSimilarIssues: + runs-on: ubuntu-latest + outputs: + message: ${{ steps.getBody.outputs.message }} + steps: + - id: getBody + uses: craigloewen-msft/GitGudSimilarIssues@main + with: + issueTitle: ${{ github.event.issue.title }} + issueBody: ${{ github.event.issue.body }} + repo: ${{ github.repository }} + similarityTolerance: "0.75" + add-comment: + needs: getSimilarIssues + runs-on: ubuntu-latest + permissions: + issues: write + if: needs.getSimilarIssues.outputs.message != '' + steps: + - name: Add comment + run: gh issue comment "$NUMBER" --repo "$REPO" --body "$BODY" + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + NUMBER: ${{ github.event.issue.number }} + REPO: ${{ github.repository }} + BODY: ${{ needs.getSimilarIssues.outputs.message }} diff --git a/.pipelines/ESRPSigning_core.json b/.pipelines/ESRPSigning_core.json index 0e6a887ec9..5c451f4b72 100644 --- a/.pipelines/ESRPSigning_core.json +++ b/.pipelines/ESRPSigning_core.json @@ -54,6 +54,7 @@ "fancyzones.dll", "PowerToys.FancyZonesEditor.exe", "PowerToys.FancyZonesEditor.dll", + "PowerToys.FancyZonesEditorCommon.dll", "PowerToys.FancyZonesModuleInterface.dll", "PowerToys.FancyZones.exe", diff --git a/.pipelines/installWiX.ps1 b/.pipelines/installWiX.ps1 index 1d8f93a7b5..3b6d783c85 100644 --- a/.pipelines/installWiX.ps1 +++ b/.pipelines/installWiX.ps1 @@ -1,19 +1,19 @@ $ProgressPreference = 'SilentlyContinue' -$WixDownloadUrl = "https://github.com/wixtoolset/wix3/releases/download/wix314rtm/wix314.exe" -$WixBinariesDownloadUrl = "https://github.com/wixtoolset/wix3/releases/download/wix314rtm/wix314-binaries.zip" +$WixDownloadUrl = "https://github.com/wixtoolset/wix3/releases/download/wix3141rtm/wix314.exe" +$WixBinariesDownloadUrl = "https://github.com/wixtoolset/wix3/releases/download/wix3141rtm/wix314-binaries.zip" # Download WiX binaries and verify their hash sums Invoke-WebRequest -Uri $WixDownloadUrl -OutFile "$($ENV:Temp)\wix314.exe" $Hash = (Get-FileHash -Algorithm SHA256 "$($ENV:Temp)\wix314.exe").Hash -if ($Hash -ne '704439EA88FC9E5A3647EEDEEB45943F9A392E3D209F58512280130096847937') +if ($Hash -ne '6BF6D03D6923D9EF827AE1D943B90B42B8EBB1B0F68EF6D55F868FA34C738A29') { Write-Error "$WixHash" throw "wix314.exe has unexpected SHA256 hash: $Hash" } Invoke-WebRequest -Uri $WixBinariesDownloadUrl -OutFile "$($ENV:Temp)\wix314-binaries.zip" $Hash = (Get-FileHash -Algorithm SHA256 "$($ENV:Temp)\wix314-binaries.zip").Hash -if($Hash -ne '13F067F38969FAF163D93A804B48EA0576790A202C8F10291F2000F0E356E934') +if($Hash -ne '6AC824E1642D6F7277D0ED7EA09411A508F6116BA6FAE0AA5F2C7DAA2FF43D31') { throw "wix314-binaries.zip has unexpected SHA256 hash: $Hash" } diff --git a/doc/devdocs/readme.md b/doc/devdocs/readme.md index fb0a7719f5..558cb5aa49 100644 --- a/doc/devdocs/readme.md +++ b/doc/devdocs/readme.md @@ -80,8 +80,8 @@ The installer can only be compiled in `Release` mode; steps 1 and 2 must be perf ### Prerequisites for building the MSI installer 1. Install the [WiX Toolset Visual Studio 2022 Extension](https://marketplace.visualstudio.com/items?itemName=WixToolset.WixToolsetVisualStudio2022Extension). -1. Install the [WiX Toolset build tools](https://github.com/wixtoolset/wix3/releases/tag/wix314rtm). (installer [direct link](https://github.com/wixtoolset/wix3/releases/download/wix314rtm/wix314.exe)) -1. Download [WiX binaries](https://github.com/wixtoolset/wix3/releases/download/wix314rtm/wix314-binaries.zip) and extract `wix.targets` to `C:\Program Files (x86)\WiX Toolset v3.14`. +1. Install the [WiX Toolset build tools](https://github.com/wixtoolset/wix3/releases/tag/wix3141rtm). (installer [direct link](https://github.com/wixtoolset/wix3/releases/download/wix3141rtm/wix314.exe)) +1. Download [WiX binaries](https://github.com/wixtoolset/wix3/releases/download/wix3141rtm/wix314-binaries.zip) and extract `wix.targets` to `C:\Program Files (x86)\WiX Toolset v3.14`. ### Building prerequisite projects diff --git a/installer/PowerToysSetup/PowerToys.wxs b/installer/PowerToysSetup/PowerToys.wxs index bb4d820ba4..2e50d278fb 100644 --- a/installer/PowerToysSetup/PowerToys.wxs +++ b/installer/PowerToysSetup/PowerToys.wxs @@ -68,7 +68,7 @@ Vital="no"> diff --git a/src/modules/PowerOCR/PowerOCR/Helpers/ImageMethods.cs b/src/modules/PowerOCR/PowerOCR/Helpers/ImageMethods.cs index 241e1f7433..59ddd4b2c2 100644 --- a/src/modules/PowerOCR/PowerOCR/Helpers/ImageMethods.cs +++ b/src/modules/PowerOCR/PowerOCR/Helpers/ImageMethods.cs @@ -47,51 +47,17 @@ internal sealed class ImageMethods return destination; } - internal static ImageSource GetWindowBoundsImage(Window passedWindow) + internal static ImageSource GetWindowBoundsImage(OCROverlay passedWindow) { - DpiScale dpi = VisualTreeHelper.GetDpi(passedWindow); - int windowWidth = (int)(passedWindow.ActualWidth * dpi.DpiScaleX); - int windowHeight = (int)(passedWindow.ActualHeight * dpi.DpiScaleY); - - System.Windows.Point absPosPoint = passedWindow.GetAbsolutePosition(); - int thisCorrectedLeft = (int)absPosPoint.X; - int thisCorrectedTop = (int)absPosPoint.Y; - - using Bitmap bmp = new(windowWidth, windowHeight, System.Drawing.Imaging.PixelFormat.Format32bppArgb); + Rectangle screenRectangle = passedWindow.GetScreenRectangle(); + using Bitmap bmp = new(screenRectangle.Width, screenRectangle.Height, System.Drawing.Imaging.PixelFormat.Format32bppArgb); using Graphics g = Graphics.FromImage(bmp); - g.CopyFromScreen(thisCorrectedLeft, thisCorrectedTop, 0, 0, bmp.Size, CopyPixelOperation.SourceCopy); + g.CopyFromScreen(screenRectangle.Left, screenRectangle.Top, 0, 0, bmp.Size, CopyPixelOperation.SourceCopy); return BitmapToImageSource(bmp); } - internal static Bitmap GetWindowBoundsBitmap(Window passedWindow) - { - DpiScale dpi = VisualTreeHelper.GetDpi(passedWindow); - int windowWidth = (int)(passedWindow.ActualWidth * dpi.DpiScaleX); - int windowHeight = (int)(passedWindow.ActualHeight * dpi.DpiScaleY); - - System.Windows.Point absPosPoint = passedWindow.GetAbsolutePosition(); - int thisCorrectedLeft = (int)absPosPoint.X; - int thisCorrectedTop = (int)absPosPoint.Y; - - Bitmap bmp = new( - windowWidth, - windowHeight, - System.Drawing.Imaging.PixelFormat.Format32bppArgb); - using Graphics g = Graphics.FromImage(bmp); - - g.CopyFromScreen( - thisCorrectedLeft, - thisCorrectedTop, - 0, - 0, - bmp.Size, - CopyPixelOperation.SourceCopy); - - return bmp; - } - - internal static Bitmap GetRegionAsBitmap(Window passedWindow, Rectangle selectedRegion) + internal static Bitmap GetRegionAsBitmap(OCROverlay passedWindow, Rectangle selectedRegion) { Bitmap bmp = new( selectedRegion.Width, @@ -99,15 +65,11 @@ internal sealed class ImageMethods System.Drawing.Imaging.PixelFormat.Format32bppArgb); using Graphics g = Graphics.FromImage(bmp); - - System.Windows.Point absPosPoint = passedWindow.GetAbsolutePosition(); - - int thisCorrectedLeft = (int)absPosPoint.X + selectedRegion.Left; - int thisCorrectedTop = (int)absPosPoint.Y + selectedRegion.Top; + Rectangle screenRectangle = passedWindow.GetScreenRectangle(); g.CopyFromScreen( - thisCorrectedLeft, - thisCorrectedTop, + screenRectangle.Left + selectedRegion.Left, + screenRectangle.Top + selectedRegion.Top, 0, 0, bmp.Size, @@ -117,7 +79,7 @@ internal sealed class ImageMethods return bmp; } - internal static async Task GetRegionsText(Window? passedWindow, Rectangle selectedRegion, Language? preferredLanguage) + internal static async Task GetRegionsText(OCROverlay? passedWindow, Rectangle selectedRegion, Language? preferredLanguage) { if (passedWindow is null) { @@ -130,17 +92,15 @@ internal sealed class ImageMethods return resultText != null ? resultText.Trim() : string.Empty; } - internal static async Task GetClickedWord(Window passedWindow, System.Windows.Point clickedPoint, Language? preferredLanguage) + internal static async Task GetClickedWord(OCROverlay passedWindow, System.Windows.Point clickedPoint, Language? preferredLanguage) { - DpiScale dpi = VisualTreeHelper.GetDpi(passedWindow); - Bitmap bmp = new((int)(passedWindow.ActualWidth * dpi.DpiScaleX), (int)(passedWindow.ActualHeight * dpi.DpiScaleY), System.Drawing.Imaging.PixelFormat.Format32bppArgb); + Rectangle screenRectangle = passedWindow.GetScreenRectangle(); + Bitmap bmp = new((int)screenRectangle.Width, (int)passedWindow.Height, System.Drawing.Imaging.PixelFormat.Format32bppArgb); Graphics g = Graphics.FromImage(bmp); System.Windows.Point absPosPoint = passedWindow.GetAbsolutePosition(); - int thisCorrectedLeft = (int)absPosPoint.X; - int thisCorrectedTop = (int)absPosPoint.Y; - g.CopyFromScreen(thisCorrectedLeft, thisCorrectedTop, 0, 0, bmp.Size, CopyPixelOperation.SourceCopy); + g.CopyFromScreen((int)absPosPoint.X, (int)absPosPoint.Y, 0, 0, bmp.Size, CopyPixelOperation.SourceCopy); System.Windows.Point adjustedPoint = new(clickedPoint.X, clickedPoint.Y); diff --git a/src/modules/PowerOCR/PowerOCR/Helpers/OcrExtensions.cs b/src/modules/PowerOCR/PowerOCR/Helpers/OcrExtensions.cs index 3bce062178..c8a9df644a 100644 --- a/src/modules/PowerOCR/PowerOCR/Helpers/OcrExtensions.cs +++ b/src/modules/PowerOCR/PowerOCR/Helpers/OcrExtensions.cs @@ -62,7 +62,7 @@ namespace PowerOCR.Helpers } } - public static async Task GetRegionsTextAsTableAsync(Window passedWindow, Rectangle regionScaled, Language? language) + public static async Task GetRegionsTextAsTableAsync(OCROverlay passedWindow, Rectangle regionScaled, Language? language) { if (language is null) { diff --git a/src/modules/PowerOCR/PowerOCR/Helpers/WPFExtensionMethods.cs b/src/modules/PowerOCR/PowerOCR/Helpers/WPFExtensionMethods.cs index 5c7ad6a7b5..c038eae96d 100644 --- a/src/modules/PowerOCR/PowerOCR/Helpers/WPFExtensionMethods.cs +++ b/src/modules/PowerOCR/PowerOCR/Helpers/WPFExtensionMethods.cs @@ -37,4 +37,28 @@ public static class WPFExtensionMethods return new Point(r.X, r.Y); } + + public static DpiScale GetDpi(this System.Windows.Forms.Screen screen) + { + var point = new System.Drawing.Point(screen.Bounds.Left + 1, screen.Bounds.Top + 1); + var mon = MonitorFromPoint(point, 2/*MONITOR_DEFAULTTONEAREST*/); + GetDpiForMonitor(mon, DpiType.Effective, out uint dpiX, out uint dpiY); + return new DpiScale(dpiX / 96.0, dpiY / 96.0); + } + + // https://msdn.microsoft.com/library/windows/desktop/dd145062(v=vs.85).aspx + [DllImport("User32.dll")] + private static extern IntPtr MonitorFromPoint([In] System.Drawing.Point pt, [In] uint dwFlags); + + // https://msdn.microsoft.com/library/windows/desktop/dn280510(v=vs.85).aspx + [DllImport("Shcore.dll")] + private static extern IntPtr GetDpiForMonitor([In] IntPtr hmonitor, [In] DpiType dpiType, [Out] out uint dpiX, [Out] out uint dpiY); + + // https://msdn.microsoft.com/library/windows/desktop/dn280511(v=vs.85).aspx + public enum DpiType + { + Effective = 0, + Angular = 1, + Raw = 2, + } } diff --git a/src/modules/PowerOCR/PowerOCR/Helpers/WindowUtilities.cs b/src/modules/PowerOCR/PowerOCR/Helpers/WindowUtilities.cs index c62f900106..9d3fcdc605 100644 --- a/src/modules/PowerOCR/PowerOCR/Helpers/WindowUtilities.cs +++ b/src/modules/PowerOCR/PowerOCR/Helpers/WindowUtilities.cs @@ -24,8 +24,9 @@ public static class WindowUtilities Logger.LogInfo($"Adding Overlays for each screen"); foreach (Screen screen in Screen.AllScreens) { - Logger.LogInfo($"screen {screen}"); - OCROverlay overlay = new(screen.Bounds); + DpiScale dpiScale = screen.GetDpi(); + Logger.LogInfo($"screen {screen}, dpiScale {dpiScale.DpiScaleX}, {dpiScale.DpiScaleY}"); + OCROverlay overlay = new(screen.Bounds, dpiScale); overlay.Show(); ActivateWindow(overlay); diff --git a/src/modules/PowerOCR/PowerOCR/OCROverlay.xaml b/src/modules/PowerOCR/PowerOCR/OCROverlay.xaml index 100b5de9ef..19944b04bf 100644 --- a/src/modules/PowerOCR/PowerOCR/OCROverlay.xaml +++ b/src/modules/PowerOCR/PowerOCR/OCROverlay.xaml @@ -7,8 +7,6 @@ xmlns:p="clr-namespace:PowerOCR.Properties" xmlns:ui="http://schemas.lepo.co/wpfui/2022/xaml" Title="TextExtractor" - Width="200" - Height="200" ui:Design.Background="Transparent" AllowsTransparency="True" Background="Transparent" diff --git a/src/modules/PowerOCR/PowerOCR/OCROverlay.xaml.cs b/src/modules/PowerOCR/PowerOCR/OCROverlay.xaml.cs index 1c7f266169..ffce2e45e4 100644 --- a/src/modules/PowerOCR/PowerOCR/OCROverlay.xaml.cs +++ b/src/modules/PowerOCR/PowerOCR/OCROverlay.xaml.cs @@ -5,10 +5,12 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Runtime.InteropServices; using System.Windows; using System.Windows.Controls; using System.Windows.Controls.Primitives; using System.Windows.Input; +using System.Windows.Interop; using System.Windows.Media; using Common.UI; using ManagedCommon; @@ -42,11 +44,21 @@ public partial class OCROverlay : Window private bool isComboBoxReady; private const double ActiveOpacity = 0.4; private readonly UserSettings userSettings = new(new ThrottledActionInvoker()); + private System.Drawing.Rectangle screenRectangle; + private DpiScale dpiScale; - public OCROverlay(System.Drawing.Rectangle screenRectangle) + [DllImport("user32.dll", SetLastError = true)] + private static extern bool MoveWindow(IntPtr hWnd, int x, int y, int nWidth, int nHeight, bool bRepaint); + + public OCROverlay(System.Drawing.Rectangle screenRectangleParam, DpiScale dpiScaleParam) { - Left = screenRectangle.Left >= 0 ? screenRectangle.Left : screenRectangle.Left + (screenRectangle.Width / 2); - Top = screenRectangle.Top >= 0 ? screenRectangle.Top : screenRectangle.Top + (screenRectangle.Height / 2); + screenRectangle = screenRectangleParam; + dpiScale = dpiScaleParam; + + Left = screenRectangle.Left; + Top = screenRectangle.Top; + Width = screenRectangle.Width / dpiScale.DpiScaleX; + Height = screenRectangle.Height / dpiScale.DpiScaleY; InitializeComponent(); @@ -106,7 +118,6 @@ public partial class OCROverlay : Window private void Window_Loaded(object sender, RoutedEventArgs e) { - WindowState = WindowState.Maximized; FullWindow.Rect = new Rect(0, 0, Width, Height); KeyDown += MainWindow_KeyDown; KeyUp += MainWindow_KeyUp; @@ -119,6 +130,12 @@ public partial class OCROverlay : Window #if DEBUG Topmost = false; #endif + IntPtr hwnd = new WindowInteropHelper(this).Handle; + + // The first move puts it on the correct monitor, which triggers WM_DPICHANGED + // The +1/-1 coerces WPF to update Window.Top/Left/Width/Height in the second move + MoveWindow(hwnd, (int)(screenRectangle.Left + 1), (int)screenRectangle.Top, (int)(screenRectangle.Width - 1), (int)screenRectangle.Height, false); + MoveWindow(hwnd, (int)screenRectangle.Left, (int)screenRectangle.Top, (int)screenRectangle.Width, (int)screenRectangle.Height, true); } private void Window_Unloaded(object sender, RoutedEventArgs e) @@ -476,4 +493,9 @@ public partial class OCROverlay : Window break; } } + + public System.Drawing.Rectangle GetScreenRectangle() + { + return screenRectangle; + } } diff --git a/src/modules/PowerOCR/PowerOCR/app.manifest b/src/modules/PowerOCR/PowerOCR/app.manifest index 8bd61651e3..5358e351b7 100644 --- a/src/modules/PowerOCR/PowerOCR/app.manifest +++ b/src/modules/PowerOCR/PowerOCR/app.manifest @@ -47,6 +47,12 @@ + + true/pm + + PerMonitor + + diff --git a/src/modules/fancyzones/editor/FancyZonesEditor/Utils/FancyZonesEditorIO.cs b/src/modules/fancyzones/editor/FancyZonesEditor/Utils/FancyZonesEditorIO.cs index 551bbec86b..166752cab9 100644 --- a/src/modules/fancyzones/editor/FancyZonesEditor/Utils/FancyZonesEditorIO.cs +++ b/src/modules/fancyzones/editor/FancyZonesEditor/Utils/FancyZonesEditorIO.cs @@ -6,6 +6,7 @@ using System; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Globalization; +using System.IO; using System.Text.Json; using System.Windows; using FancyZonesEditor.Models; @@ -149,10 +150,13 @@ namespace FancyZonesEditor.Utils try { LayoutHotkeys parser = new LayoutHotkeys(); + if (!File.Exists(parser.File)) + { + return new ParsingResult(true); + } + var layoutHotkeys = parser.Read(parser.File); - bool layoutHotkeysParsingResult = SetLayoutHotkeys(layoutHotkeys); - if (!layoutHotkeysParsingResult) { return new ParsingResult(false, FancyZonesEditor.Properties.Resources.Error_Parsing_Layout_Hotkeys_Message); @@ -174,8 +178,12 @@ namespace FancyZonesEditor.Utils try { LayoutTemplates parser = new LayoutTemplates(); - var templates = parser.Read(parser.File); + if (!File.Exists(parser.File)) + { + return new ParsingResult(true); + } + var templates = parser.Read(parser.File); bool parsingResult = SetTemplateLayouts(templates.LayoutTemplates); if (parsingResult) { @@ -198,8 +206,12 @@ namespace FancyZonesEditor.Utils try { CustomLayouts parser = new CustomLayouts(); - var wrapper = parser.Read(parser.File); + if (!File.Exists(parser.File)) + { + return new ParsingResult(true); + } + var wrapper = parser.Read(parser.File); bool parsingResult = SetCustomLayouts(wrapper.CustomLayouts); if (parsingResult) { @@ -222,8 +234,12 @@ namespace FancyZonesEditor.Utils try { DefaultLayouts parser = new DefaultLayouts(); - var wrapper = parser.Read(parser.File); + if (!File.Exists(parser.File)) + { + return new ParsingResult(true); + } + var wrapper = parser.Read(parser.File); bool parsingResult = SetDefaultLayouts(wrapper.DefaultLayouts); if (parsingResult) { diff --git a/src/modules/peek/Peek.Common/Models/FileItem.cs b/src/modules/peek/Peek.Common/Models/FileItem.cs index 4714d30f6e..d49ead7ddd 100644 --- a/src/modules/peek/Peek.Common/Models/FileItem.cs +++ b/src/modules/peek/Peek.Common/Models/FileItem.cs @@ -3,6 +3,7 @@ // See the LICENSE file in the project root for more information. using System; +using System.Globalization; using System.Threading.Tasks; using ManagedCommon; using Windows.Storage; @@ -25,6 +26,8 @@ namespace Peek.Common.Models public string Path { get; init; } + public string Extension => System.IO.Path.GetExtension(Path).ToLower(CultureInfo.InvariantCulture); + public async Task GetStorageItemAsync() { return await GetStorageFileAsync(); diff --git a/src/modules/peek/Peek.Common/Models/FolderItem.cs b/src/modules/peek/Peek.Common/Models/FolderItem.cs index a270ff0c7b..f86adf9a73 100644 --- a/src/modules/peek/Peek.Common/Models/FolderItem.cs +++ b/src/modules/peek/Peek.Common/Models/FolderItem.cs @@ -25,6 +25,8 @@ namespace Peek.Common.Models public string Path { get; init; } + public string Extension => string.Empty; + public async Task GetStorageItemAsync() { return await GetStorageFolderAsync(); diff --git a/src/modules/peek/Peek.Common/Models/IFileSystemItem.cs b/src/modules/peek/Peek.Common/Models/IFileSystemItem.cs index d030cf90cb..c1adcc49a3 100644 --- a/src/modules/peek/Peek.Common/Models/IFileSystemItem.cs +++ b/src/modules/peek/Peek.Common/Models/IFileSystemItem.cs @@ -3,7 +3,6 @@ // See the LICENSE file in the project root for more information. using System; -using System.Globalization; using System.Threading.Tasks; using Peek.Common.Helpers; using Windows.Storage; @@ -32,7 +31,7 @@ namespace Peek.Common.Models } } - public string Extension => System.IO.Path.GetExtension(Path).ToLower(CultureInfo.InvariantCulture); + public string Extension { get; } public string Name { get; init; } diff --git a/src/modules/peek/Peek.FilePreviewer/Previewers/Archives/ArchivePreviewer.cs b/src/modules/peek/Peek.FilePreviewer/Previewers/Archives/ArchivePreviewer.cs index 73e09f77f8..87b3494bf4 100644 --- a/src/modules/peek/Peek.FilePreviewer/Previewers/Archives/ArchivePreviewer.cs +++ b/src/modules/peek/Peek.FilePreviewer/Previewers/Archives/ArchivePreviewer.cs @@ -111,9 +111,9 @@ namespace Peek.FilePreviewer.Previewers.Archives State = PreviewState.Loaded; } - public static bool IsFileTypeSupported(string fileExt) + public static bool IsItemSupported(IFileSystemItem item) { - return _supportedFileTypes.Contains(fileExt); + return _supportedFileTypes.Contains(item.Extension); } public void Dispose() diff --git a/src/modules/peek/Peek.FilePreviewer/Previewers/Drive/DrivePreviewer.cs b/src/modules/peek/Peek.FilePreviewer/Previewers/Drive/DrivePreviewer.cs index 4408f64fe6..ad89c87390 100644 --- a/src/modules/peek/Peek.FilePreviewer/Previewers/Drive/DrivePreviewer.cs +++ b/src/modules/peek/Peek.FilePreviewer/Previewers/Drive/DrivePreviewer.cs @@ -89,9 +89,9 @@ namespace Peek.FilePreviewer.Previewers.Drive State = PreviewState.Loaded; } - public static bool IsPathSupported(string path) + public static bool IsItemSupported(IFileSystemItem item) { - return DriveInfo.GetDrives().Any(d => d.Name == path); + return DriveInfo.GetDrives().Any(d => d.Name == item.Path); } private string GetDriveTypeDescription(DriveType driveType) => driveType switch diff --git a/src/modules/peek/Peek.FilePreviewer/Previewers/Interfaces/IArchivePreviewer.cs b/src/modules/peek/Peek.FilePreviewer/Previewers/Interfaces/IArchivePreviewer.cs index 0c813f60d3..8069e50c52 100644 --- a/src/modules/peek/Peek.FilePreviewer/Previewers/Interfaces/IArchivePreviewer.cs +++ b/src/modules/peek/Peek.FilePreviewer/Previewers/Interfaces/IArchivePreviewer.cs @@ -8,7 +8,7 @@ using Peek.FilePreviewer.Previewers.Archives.Models; namespace Peek.FilePreviewer.Previewers.Interfaces { - public interface IArchivePreviewer : IPreviewer, IDisposable + public interface IArchivePreviewer : IPreviewer, IPreviewTarget, IDisposable { ObservableCollection Tree { get; } diff --git a/src/modules/peek/Peek.FilePreviewer/Previewers/Interfaces/IAudioPreviewer.cs b/src/modules/peek/Peek.FilePreviewer/Previewers/Interfaces/IAudioPreviewer.cs index 8e728dd321..d3419d1655 100644 --- a/src/modules/peek/Peek.FilePreviewer/Previewers/Interfaces/IAudioPreviewer.cs +++ b/src/modules/peek/Peek.FilePreviewer/Previewers/Interfaces/IAudioPreviewer.cs @@ -6,7 +6,7 @@ using Peek.FilePreviewer.Previewers.MediaPreviewer.Models; namespace Peek.FilePreviewer.Previewers.Interfaces { - public interface IAudioPreviewer : IPreviewer + public interface IAudioPreviewer : IPreviewer, IPreviewTarget { public AudioPreviewData? Preview { get; } } diff --git a/src/modules/peek/Peek.FilePreviewer/Previewers/Interfaces/IBrowserPreviewer.cs b/src/modules/peek/Peek.FilePreviewer/Previewers/Interfaces/IBrowserPreviewer.cs index 291c4a9823..dfbbe3ca67 100644 --- a/src/modules/peek/Peek.FilePreviewer/Previewers/Interfaces/IBrowserPreviewer.cs +++ b/src/modules/peek/Peek.FilePreviewer/Previewers/Interfaces/IBrowserPreviewer.cs @@ -4,9 +4,9 @@ using System; -namespace Peek.FilePreviewer.Previewers +namespace Peek.FilePreviewer.Previewers.Interfaces { - public interface IBrowserPreviewer : IPreviewer + public interface IBrowserPreviewer : IPreviewer, IPreviewTarget { public Uri? Preview { get; } diff --git a/src/modules/peek/Peek.FilePreviewer/Previewers/Interfaces/IDrivePreviewer.cs b/src/modules/peek/Peek.FilePreviewer/Previewers/Interfaces/IDrivePreviewer.cs index 2624311955..bd34271a1f 100644 --- a/src/modules/peek/Peek.FilePreviewer/Previewers/Interfaces/IDrivePreviewer.cs +++ b/src/modules/peek/Peek.FilePreviewer/Previewers/Interfaces/IDrivePreviewer.cs @@ -6,7 +6,7 @@ using Peek.FilePreviewer.Previewers.Drive.Models; namespace Peek.FilePreviewer.Previewers.Interfaces { - public interface IDrivePreviewer : IPreviewer + public interface IDrivePreviewer : IPreviewer, IPreviewTarget { public DrivePreviewData? Preview { get; } } diff --git a/src/modules/peek/Peek.FilePreviewer/Previewers/Interfaces/IImagePreviewer.cs b/src/modules/peek/Peek.FilePreviewer/Previewers/Interfaces/IImagePreviewer.cs index 23fa1b0871..cce81e4b8e 100644 --- a/src/modules/peek/Peek.FilePreviewer/Previewers/Interfaces/IImagePreviewer.cs +++ b/src/modules/peek/Peek.FilePreviewer/Previewers/Interfaces/IImagePreviewer.cs @@ -7,7 +7,7 @@ using Windows.Foundation; namespace Peek.FilePreviewer.Previewers.Interfaces { - public interface IImagePreviewer : IPreviewer + public interface IImagePreviewer : IPreviewer, IPreviewTarget { public ImageSource? Preview { get; } diff --git a/src/modules/peek/Peek.FilePreviewer/Previewers/Interfaces/IPreviewTarget.cs b/src/modules/peek/Peek.FilePreviewer/Previewers/Interfaces/IPreviewTarget.cs new file mode 100644 index 0000000000..7a706519e6 --- /dev/null +++ b/src/modules/peek/Peek.FilePreviewer/Previewers/Interfaces/IPreviewTarget.cs @@ -0,0 +1,13 @@ +// 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 Peek.Common.Models; + +namespace Peek.FilePreviewer.Previewers.Interfaces +{ + public interface IPreviewTarget + { + static abstract bool IsItemSupported(IFileSystemItem item); + } +} diff --git a/src/modules/peek/Peek.FilePreviewer/Previewers/Interfaces/IPreviewer.cs b/src/modules/peek/Peek.FilePreviewer/Previewers/Interfaces/IPreviewer.cs index 348c39d987..b6a74afdad 100644 --- a/src/modules/peek/Peek.FilePreviewer/Previewers/Interfaces/IPreviewer.cs +++ b/src/modules/peek/Peek.FilePreviewer/Previewers/Interfaces/IPreviewer.cs @@ -2,12 +2,10 @@ // 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.ComponentModel; using System.Threading; using System.Threading.Tasks; using Peek.FilePreviewer.Models; -using Windows.Foundation; namespace Peek.FilePreviewer.Previewers { @@ -15,8 +13,6 @@ namespace Peek.FilePreviewer.Previewers { PreviewState State { get; set; } - public static bool IsFileTypeSupported(string fileExt) => throw new NotImplementedException(); - public Task GetPreviewSizeAsync(CancellationToken cancellationToken); Task LoadPreviewAsync(CancellationToken cancellationToken); diff --git a/src/modules/peek/Peek.FilePreviewer/Previewers/Interfaces/IShellPreviewHandlerPreviewer.cs b/src/modules/peek/Peek.FilePreviewer/Previewers/Interfaces/IShellPreviewHandlerPreviewer.cs index 3d71ea926a..f5631fa9f1 100644 --- a/src/modules/peek/Peek.FilePreviewer/Previewers/Interfaces/IShellPreviewHandlerPreviewer.cs +++ b/src/modules/peek/Peek.FilePreviewer/Previewers/Interfaces/IShellPreviewHandlerPreviewer.cs @@ -4,9 +4,9 @@ using Windows.Win32.UI.Shell; -namespace Peek.FilePreviewer.Previewers +namespace Peek.FilePreviewer.Previewers.Interfaces { - public interface IShellPreviewHandlerPreviewer : IPreviewer + public interface IShellPreviewHandlerPreviewer : IPreviewer, IPreviewTarget { public IPreviewHandler? Preview { get; } diff --git a/src/modules/peek/Peek.FilePreviewer/Previewers/Interfaces/IVideoPreviewer.cs b/src/modules/peek/Peek.FilePreviewer/Previewers/Interfaces/IVideoPreviewer.cs index ae7d26d1b1..4d2b4f4f8a 100644 --- a/src/modules/peek/Peek.FilePreviewer/Previewers/Interfaces/IVideoPreviewer.cs +++ b/src/modules/peek/Peek.FilePreviewer/Previewers/Interfaces/IVideoPreviewer.cs @@ -6,7 +6,7 @@ using Windows.Media.Core; namespace Peek.FilePreviewer.Previewers.Interfaces { - public interface IVideoPreviewer : IPreviewer + public interface IVideoPreviewer : IPreviewer, IPreviewTarget { public MediaSource? Preview { get; } } diff --git a/src/modules/peek/Peek.FilePreviewer/Previewers/MediaPreviewer/AudioPreviewer.cs b/src/modules/peek/Peek.FilePreviewer/Previewers/MediaPreviewer/AudioPreviewer.cs index 696efe906a..73a430be56 100644 --- a/src/modules/peek/Peek.FilePreviewer/Previewers/MediaPreviewer/AudioPreviewer.cs +++ b/src/modules/peek/Peek.FilePreviewer/Previewers/MediaPreviewer/AudioPreviewer.cs @@ -154,9 +154,9 @@ namespace Peek.FilePreviewer.Previewers.MediaPreviewer }); } - public static bool IsFileTypeSupported(string fileExt) + public static bool IsItemSupported(IFileSystemItem item) { - return _supportedFileTypes.Contains(fileExt); + return _supportedFileTypes.Contains(item.Extension); } private static readonly HashSet _supportedFileTypes = new() diff --git a/src/modules/peek/Peek.FilePreviewer/Previewers/MediaPreviewer/ImagePreviewer.cs b/src/modules/peek/Peek.FilePreviewer/Previewers/MediaPreviewer/ImagePreviewer.cs index 2a34132f89..d29bcce110 100644 --- a/src/modules/peek/Peek.FilePreviewer/Previewers/MediaPreviewer/ImagePreviewer.cs +++ b/src/modules/peek/Peek.FilePreviewer/Previewers/MediaPreviewer/ImagePreviewer.cs @@ -70,9 +70,9 @@ namespace Peek.FilePreviewer.Previewers private ImageSource? highQualityThumbnailPreview; - public static bool IsFileTypeSupported(string fileExt) + public static bool IsItemSupported(IFileSystemItem item) { - return _supportedFileTypes.Contains(fileExt); + return _supportedFileTypes.Contains(item.Extension); } public void Dispose() diff --git a/src/modules/peek/Peek.FilePreviewer/Previewers/MediaPreviewer/VideoPreviewer.cs b/src/modules/peek/Peek.FilePreviewer/Previewers/MediaPreviewer/VideoPreviewer.cs index 77a26f7225..0cf4ea5e78 100644 --- a/src/modules/peek/Peek.FilePreviewer/Previewers/MediaPreviewer/VideoPreviewer.cs +++ b/src/modules/peek/Peek.FilePreviewer/Previewers/MediaPreviewer/VideoPreviewer.cs @@ -42,9 +42,9 @@ namespace Peek.FilePreviewer.Previewers private Task? VideoTask { get; set; } - public static bool IsFileTypeSupported(string fileExt) + public static bool IsItemSupported(IFileSystemItem item) { - return _supportedFileTypes.Contains(fileExt); + return _supportedFileTypes.Contains(item.Extension); } public void Dispose() diff --git a/src/modules/peek/Peek.FilePreviewer/Previewers/PreviewerFactory.cs b/src/modules/peek/Peek.FilePreviewer/Previewers/PreviewerFactory.cs index 23f54e846d..158521b3ca 100644 --- a/src/modules/peek/Peek.FilePreviewer/Previewers/PreviewerFactory.cs +++ b/src/modules/peek/Peek.FilePreviewer/Previewers/PreviewerFactory.cs @@ -23,39 +23,39 @@ namespace Peek.FilePreviewer.Previewers _previewSettings = Application.Current.GetService(); } - public IPreviewer Create(IFileSystemItem file) + public IPreviewer Create(IFileSystemItem item) { - if (ImagePreviewer.IsFileTypeSupported(file.Extension)) + if (ImagePreviewer.IsItemSupported(item)) { - return new ImagePreviewer(file); + return new ImagePreviewer(item); } - else if (VideoPreviewer.IsFileTypeSupported(file.Extension)) + else if (VideoPreviewer.IsItemSupported(item)) { - return new VideoPreviewer(file); + return new VideoPreviewer(item); } - else if (AudioPreviewer.IsFileTypeSupported(file.Extension)) + else if (AudioPreviewer.IsItemSupported(item)) { - return new AudioPreviewer(file); + return new AudioPreviewer(item); } - else if (WebBrowserPreviewer.IsFileTypeSupported(file.Extension)) + else if (WebBrowserPreviewer.IsItemSupported(item)) { - return new WebBrowserPreviewer(file, _previewSettings); + return new WebBrowserPreviewer(item, _previewSettings); } - else if (ArchivePreviewer.IsFileTypeSupported(file.Extension)) + else if (ArchivePreviewer.IsItemSupported(item)) { - return new ArchivePreviewer(file); + return new ArchivePreviewer(item); } - else if (ShellPreviewHandlerPreviewer.IsFileTypeSupported(file.Extension)) + else if (ShellPreviewHandlerPreviewer.IsItemSupported(item)) { - return new ShellPreviewHandlerPreviewer(file); + return new ShellPreviewHandlerPreviewer(item); } - else if (DrivePreviewer.IsPathSupported(file.Path)) + else if (DrivePreviewer.IsItemSupported(item)) { - return new DrivePreviewer(file); + return new DrivePreviewer(item); } // Other previewer types check their supported file types here - return CreateDefaultPreviewer(file); + return CreateDefaultPreviewer(item); } public IPreviewer CreateDefaultPreviewer(IFileSystemItem file) diff --git a/src/modules/peek/Peek.FilePreviewer/Previewers/ShellPreviewHandlerPreviewer/ShellPreviewHandlerPreviewer.cs b/src/modules/peek/Peek.FilePreviewer/Previewers/ShellPreviewHandlerPreviewer/ShellPreviewHandlerPreviewer.cs index 1d13c4412d..0e1eb5c90f 100644 --- a/src/modules/peek/Peek.FilePreviewer/Previewers/ShellPreviewHandlerPreviewer/ShellPreviewHandlerPreviewer.cs +++ b/src/modules/peek/Peek.FilePreviewer/Previewers/ShellPreviewHandlerPreviewer/ShellPreviewHandlerPreviewer.cs @@ -16,6 +16,7 @@ using Peek.Common.Helpers; using Peek.Common.Models; using Peek.FilePreviewer.Models; using Peek.FilePreviewer.Previewers.Helpers; +using Peek.FilePreviewer.Previewers.Interfaces; using Windows.Win32; using Windows.Win32.System.Com; using Windows.Win32.UI.Shell; @@ -205,9 +206,9 @@ namespace Peek.FilePreviewer.Previewers } } - public static bool IsFileTypeSupported(string fileExt) + public static bool IsItemSupported(IFileSystemItem item) { - return !string.IsNullOrEmpty(GetPreviewHandlerGuid(fileExt)); + return !string.IsNullOrEmpty(GetPreviewHandlerGuid(item.Extension)); } private static string? GetPreviewHandlerGuid(string fileExt) diff --git a/src/modules/peek/Peek.FilePreviewer/Previewers/WebBrowserPreviewer/WebBrowserPreviewer.cs b/src/modules/peek/Peek.FilePreviewer/Previewers/WebBrowserPreviewer/WebBrowserPreviewer.cs index adbcd8eb4c..0d29c874fd 100644 --- a/src/modules/peek/Peek.FilePreviewer/Previewers/WebBrowserPreviewer/WebBrowserPreviewer.cs +++ b/src/modules/peek/Peek.FilePreviewer/Previewers/WebBrowserPreviewer/WebBrowserPreviewer.cs @@ -13,6 +13,7 @@ using Peek.Common.Extensions; using Peek.Common.Helpers; using Peek.Common.Models; using Peek.FilePreviewer.Models; +using Peek.FilePreviewer.Previewers.Interfaces; namespace Peek.FilePreviewer.Previewers { @@ -137,9 +138,9 @@ namespace Peek.FilePreviewer.Previewers }); } - public static bool IsFileTypeSupported(string fileExt) + public static bool IsItemSupported(IFileSystemItem item) { - return _supportedFileTypes.Contains(fileExt) || MonacoHelper.SupportedMonacoFileTypes.Contains(fileExt); + return _supportedFileTypes.Contains(item.Extension) || MonacoHelper.SupportedMonacoFileTypes.Contains(item.Extension); } private bool HasFailedLoadingPreview() diff --git a/src/modules/registrypreview/RegistryPreviewUI/MainWindow.Events.cs b/src/modules/registrypreview/RegistryPreviewUI/MainWindow.Events.cs index 420b4fd01a..dadcdd2a0e 100644 --- a/src/modules/registrypreview/RegistryPreviewUI/MainWindow.Events.cs +++ b/src/modules/registrypreview/RegistryPreviewUI/MainWindow.Events.cs @@ -155,7 +155,9 @@ namespace RegistryPreview // Pull in a new REG file - we have to use the direct Win32 method because FileOpenPicker crashes when it's // called while running as admin + IntPtr windowHandle = WinRT.Interop.WindowNative.GetWindowHandle(this); string filename = OpenFilePicker.ShowDialog( + windowHandle, resourceLoader.GetString("FilterRegistryName") + '\0' + "*.reg" + '\0' + resourceLoader.GetString("FilterAllFiles") + '\0' + "*.*" + '\0' + '\0', resourceLoader.GetString("OpenDialogTitle")); @@ -197,7 +199,9 @@ namespace RegistryPreview { // Save out a new REG file and then open it - we have to use the direct Win32 method because FileOpenPicker crashes when it's // called while running as admin + IntPtr windowHandle = WinRT.Interop.WindowNative.GetWindowHandle(this); string filename = SaveFilePicker.ShowDialog( + windowHandle, resourceLoader.GetString("SuggestFileName"), resourceLoader.GetString("FilterRegistryName") + '\0' + "*.reg" + '\0' + resourceLoader.GetString("FilterAllFiles") + '\0' + "*.*" + '\0' + '\0', resourceLoader.GetString("SaveDialogTitle")); diff --git a/src/modules/registrypreview/RegistryPreviewUI/OpenFileName.cs b/src/modules/registrypreview/RegistryPreviewUI/OpenFileName.cs index c6dc243aeb..77f3354886 100644 --- a/src/modules/registrypreview/RegistryPreviewUI/OpenFileName.cs +++ b/src/modules/registrypreview/RegistryPreviewUI/OpenFileName.cs @@ -2,6 +2,7 @@ // 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.Runtime.InteropServices; namespace RegistryPreview @@ -13,11 +14,12 @@ namespace RegistryPreview [DllImport("comdlg32.dll", SetLastError = true, CharSet = CharSet.Auto)] private static extern bool GetOpenFileName(ref FileName openFileName); - public static string ShowDialog(string filter, string dialogTitle) + public static string ShowDialog(IntPtr windowHandle, string filter, string dialogTitle) { FileName openFileName = default(FileName); openFileName.StructSize = Marshal.SizeOf(openFileName); + openFileName.HwndOwner = windowHandle; openFileName.Filter = filter; openFileName.File = new string(new char[256]); openFileName.MaxFile = openFileName.File.Length; diff --git a/src/modules/registrypreview/RegistryPreviewUI/SaveFileName.cs b/src/modules/registrypreview/RegistryPreviewUI/SaveFileName.cs index 0e0f2d58a7..ce29f48d1d 100644 --- a/src/modules/registrypreview/RegistryPreviewUI/SaveFileName.cs +++ b/src/modules/registrypreview/RegistryPreviewUI/SaveFileName.cs @@ -2,6 +2,7 @@ // 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.Runtime.InteropServices; namespace RegistryPreview @@ -13,11 +14,12 @@ namespace RegistryPreview [DllImport("comdlg32.dll", SetLastError = true, CharSet = CharSet.Auto)] private static extern bool GetSaveFileName(ref FileName saveFileName); - public static string ShowDialog(string suggestedFilename, string filter, string dialogTitle) + public static string ShowDialog(IntPtr windowHandle, string suggestedFilename, string filter, string dialogTitle) { FileName saveFileName = default(FileName); saveFileName.StructSize = Marshal.SizeOf(saveFileName); + saveFileName.HwndOwner = windowHandle; saveFileName.Filter = filter; saveFileName.File = new string(new char[256]); saveFileName.MaxFile = saveFileName.File.Length;