Skip to content

Instantly share code, notes, and snippets.

@luojunyuan
Last active January 28, 2023 06:48
Show Gist options
  • Save luojunyuan/d7cee85b8535547f8625a3f6d61eea3d to your computer and use it in GitHub Desktop.
Save luojunyuan/d7cee85b8535547f8625a3f6d61eea3d to your computer and use it in GitHub Desktop.
using System.Windows.Threading;
using System.Windows;
using System.Windows.Interop;
namespace MagnifierWpf;
public class MagWindow : Window
{
private float magnification;
private int _sourceWidth = 400;
private int _sourceHeight = 50;
private static double StableScreenWidth = NativeMethods.GetSystemMetrics(NativeMethods.SM_CXSCREEN);
private static double StableScreenHeight = NativeMethods.GetSystemMetrics(NativeMethods.SM_CYSCREEN);
public MagWindow()
{
// DPI に関わる
var dpi = 2;
var screenWidth = StableScreenWidth / dpi;
var screenHeight = StableScreenHeight / dpi;
magnification = screenWidth / _sourceWidth;
Console.WriteLine($"Scale x{magnification}");
Left = 0;
Width = screenWidth;
Height = _sourceHeight * magnification;
Top = screenHeight - Height;
AllowsTransparency = true;
WindowStyle = WindowStyle.None;
Background = System.Windows.Media.Brushes.Transparent;
Loaded += MagWindowOnLoaded;
Closed += MagWindowOnClosed;
}
private RECT _magWindowRect = new RECT();
private nint _handle;
private DispatcherTimer _timer = new();
private nint _hwndMag;
private void MagWindowOnLoaded(object? sender, RoutedEventArgs e)
{
// 順番 initialize -> Setuo -> Start timer
var initialized = NativeMethods.MagInitialize();
if (initialized)
{
// Just like a fill parameter
var hInst = NativeMethods.GetModuleHandle(null);
_handle = new WindowInteropHelper(this).Handle;
// Create a magnifier control that fills the client area.
NativeMethods.GetClientRect(_handle, ref _magWindowRect); // _magWindowRect get the window height width
_hwndMag = NativeMethods.CreateWindow(
(int)ExtendedWindowStyles.WS_EX_CLIENTEDGE,
NativeMethods.WC_MAGNIFIER,
"MagnifierWindow",
(int)WindowStyles.WS_CHILD | (int)MagnifierStyle.MS_SHOWMAGNIFIEDCURSOR | (int)WindowStyles.WS_VISIBLE,
_magWindowRect.left, _magWindowRect.top, _magWindowRect.right, _magWindowRect.bottom,
_handle, // this parameter bind to wpf window
IntPtr.Zero, hInst, IntPtr.Zero);
if (_hwndMag == IntPtr.Zero)
{
throw new ArgumentNullException();
}
// var isSmoothingActive = NativeMethods.MagSetLensUseBitmapSmoothing(_hwndMag, true);
// Set the magnification factor.
Transformation matrix = new Transformation(magnification);
NativeMethods.MagSetWindowTransform(_hwndMag, ref matrix);
_timer.Tick += UpdateMaginifier;
_timer.Interval = TimeSpan.FromMilliseconds(NativeMethods.USER_TIMER_MINIMUM);
_timer.Start();
}
}
private void UpdateMaginifier(object? sender, EventArgs e)
{
// NativeMethods.GetSystemMetrics(NativeMethods.SM_CXSCREEN)
RECT sourceRect = new RECT();
sourceRect.left = 0;
sourceRect.top = 0;
sourceRect.right = sourceRect.left + _sourceWidth;
sourceRect.bottom = sourceRect.top + _sourceHeight;
// Set the source rectangle for the magnifier control.
NativeMethods.MagSetWindowSource(_hwndMag, sourceRect);
// Reclaim topmost status, to prevent unmagnified menus from remaining in view.
NativeMethods.SetWindowPos(
_handle,
NativeMethods.HWND_TOPMOST, 0, 0, 0, 0,
(int)SetWindowPosFlags.SWP_NOACTIVATE | (int)SetWindowPosFlags.SWP_NOMOVE | (int)SetWindowPosFlags.SWP_NOSIZE);
// Force redraw.
NativeMethods.InvalidateRect(_hwndMag, IntPtr.Zero, true);
}
private void MagWindowOnClosed(object? sender, EventArgs e)
{
_timer.Stop();
NativeMethods.MagUninitialize();
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment