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;