diff --git a/.github/actions/spell-check/expect.txt b/.github/actions/spell-check/expect.txt
index 58556bb989..2f1bcde7f8 100644
--- a/.github/actions/spell-check/expect.txt
+++ b/.github/actions/spell-check/expect.txt
@@ -1017,6 +1017,7 @@ MERGEPAINT
Metacharacter
metadatamatters
Metadatas
+Metacharacter
metafile
mfc
Mgmt
diff --git a/src/modules/Workspaces/WorkspacesEditor/OverlayWindow.xaml.cs b/src/modules/Workspaces/WorkspacesEditor/OverlayWindow.xaml.cs
index 54e892d9bd..d1646e7282 100644
--- a/src/modules/Workspaces/WorkspacesEditor/OverlayWindow.xaml.cs
+++ b/src/modules/Workspaces/WorkspacesEditor/OverlayWindow.xaml.cs
@@ -2,8 +2,11 @@
// 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.Windows;
+using WorkspacesEditor.Utils;
+
namespace WorkspacesEditor
{
///
@@ -11,9 +14,40 @@ namespace WorkspacesEditor
///
public partial class OverlayWindow : Window
{
+ private int _targetX;
+ private int _targetY;
+ private int _targetWidth;
+ private int _targetHeight;
+
public OverlayWindow()
{
InitializeComponent();
+ SourceInitialized += OnWindowSourceInitialized;
+ }
+
+ ///
+ /// Sets the target bounds for the overlay window.
+ /// The window will be positioned using DPI-unaware context after initialization.
+ ///
+ public void SetTargetBounds(int x, int y, int width, int height)
+ {
+ _targetX = x;
+ _targetY = y;
+ _targetWidth = width;
+ _targetHeight = height;
+
+ // Set initial WPF properties (will be corrected after HWND creation)
+ Left = x;
+ Top = y;
+ Width = width;
+ Height = height;
+ }
+
+ private void OnWindowSourceInitialized(object sender, EventArgs e)
+ {
+ // Reposition window using DPI-unaware context to match the virtual coordinates.
+ // This fixes overlay positioning on mixed-DPI multi-monitor setups.
+ NativeMethods.SetWindowPositionDpiUnaware(this, _targetX, _targetY, _targetWidth, _targetHeight);
}
}
}
diff --git a/src/modules/Workspaces/WorkspacesEditor/Utils/NativeMethods.cs b/src/modules/Workspaces/WorkspacesEditor/Utils/NativeMethods.cs
index 4105cbe959..9687aeac63 100644
--- a/src/modules/Workspaces/WorkspacesEditor/Utils/NativeMethods.cs
+++ b/src/modules/Workspaces/WorkspacesEditor/Utils/NativeMethods.cs
@@ -4,6 +4,8 @@
using System;
using System.Runtime.InteropServices;
+using System.Windows;
+using System.Windows.Interop;
namespace WorkspacesEditor.Utils
{
@@ -17,6 +19,39 @@ namespace WorkspacesEditor.Utils
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool MoveWindow(IntPtr hWnd, int X, int Y, int nWidth, int nHeight, bool bRepaint);
+ [DllImport("user32.dll", SetLastError = true)]
+ private static extern bool SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, int X, int Y, int cx, int cy, uint uFlags);
+
+ [DllImport("user32.dll")]
+ private static extern IntPtr SetThreadDpiAwarenessContext(IntPtr dpiContext);
+
+ private const uint SWP_NOZORDER = 0x0004;
+ private const uint SWP_NOACTIVATE = 0x0010;
+
+ private static readonly IntPtr DPI_AWARENESS_CONTEXT_UNAWARE = new IntPtr(-1);
+
+ ///
+ /// Positions a WPF window using DPI-unaware context to match the virtual coordinates.
+ /// This fixes overlay positioning on mixed-DPI multi-monitor setups.
+ ///
+ public static void SetWindowPositionDpiUnaware(Window window, int x, int y, int width, int height)
+ {
+ var helper = new WindowInteropHelper(window).Handle;
+ if (helper != IntPtr.Zero)
+ {
+ // Temporarily switch to DPI-unaware context to position window.
+ IntPtr oldContext = SetThreadDpiAwarenessContext(DPI_AWARENESS_CONTEXT_UNAWARE);
+ try
+ {
+ SetWindowPos(helper, IntPtr.Zero, x, y, width, height, SWP_NOZORDER | SWP_NOACTIVATE);
+ }
+ finally
+ {
+ SetThreadDpiAwarenessContext(oldContext);
+ }
+ }
+ }
+
[DllImport("USER32.DLL")]
public static extern bool SetForegroundWindow(IntPtr hWnd);
diff --git a/src/modules/Workspaces/WorkspacesEditor/ViewModels/MainViewModel.cs b/src/modules/Workspaces/WorkspacesEditor/ViewModels/MainViewModel.cs
index 9c76c26fa0..5741fd65ab 100644
--- a/src/modules/Workspaces/WorkspacesEditor/ViewModels/MainViewModel.cs
+++ b/src/modules/Workspaces/WorkspacesEditor/ViewModels/MainViewModel.cs
@@ -495,10 +495,10 @@ namespace WorkspacesEditor.ViewModels
{
var bounds = screen.Bounds;
OverlayWindow overlayWindow = new OverlayWindow();
- overlayWindow.Top = bounds.Top;
- overlayWindow.Left = bounds.Left;
- overlayWindow.Width = bounds.Width;
- overlayWindow.Height = bounds.Height;
+
+ // Use DPI-unaware positioning to fix overlay on mixed-DPI multi-monitor setups
+ overlayWindow.SetTargetBounds(bounds.Left, bounds.Top, bounds.Width, bounds.Height);
+
overlayWindow.ShowActivated = true;
overlayWindow.Topmost = true;
overlayWindow.Show();