0

I want to be able to perform lens magnificaiton on top of the windows taskbar. So far I've been unsuccessful in implementing this seeing as the taskbar will always open on top of my window. Windows built-in magnifier is able to do this so I'm hoping it is indeed possible.

I've attached two screenshots showing Windows built-in magnifier and how it is able to magnify the taskbar and how my application will render below the taskbar.

Windows built-in Magnifier:

Windows built-in Magnifier

My application:

My application

Is there any way to have my application render above the taskbar and thus magnify the taskbar?

<Window x:Class="WpfNativeTesting.MagnificationWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:WpfNativeTesting"
        mc:Ignorable="d"
        Title="MagnificationWindow"
        
        Height="400"
        Width="400"
        
        WindowStyle="None"
        ResizeMode="NoResize"
        AllowsTransparency="true"
        ShowInTaskbar="False"
        Topmost="True">
    <Grid x:Name="ContainerGrid">
        <Grid x:Name="MagnificationGrid" />
    </Grid>
</Window>
public partial class MagnificationWindow : Window
    {
        private IntPtr HWnd;
        private IntPtr HWndMag;
        private bool MagnificationInitialized = false;
        private DispatcherTimer Timer = new DispatcherTimer();
        private RECT MagWindowRect = new RECT();
        private bool IsColorEffectSet = false;

        private float magnification = 1.0f;
        public float Magnification
        {
            get { return magnification; }
            set
            {
                if (value < 1.0f)
                {
                    value = 1.0f;
                }

                if (HWndMag != null)
                {
                    if (magnification != value)
                    {
                        magnification = value;

                        Transformation matrix = new Transformation(magnification);
                        NativeMethods.MagSetWindowTransform(HWndMag, ref matrix);
                    }
                }
            }
        }

        public MagnificationWindow()
        {
            InitializeComponent();

            Loaded += MagnificationWindow_Loaded;

            Show();
        }

        private void MagnificationWindow_Loaded(object sender, RoutedEventArgs e)
        {
            HWnd = new WindowInteropHelper(this).Handle;

            var exStyle = NativeMethods.GetWindowLong(HWnd, NativeMethods.GWL_EXSTYLE);
            exStyle |= (int)ExtendedWindowStyles.WS_EX_TOPMOST | (int)ExtendedWindowStyles.WS_EX_LAYERED | (int)ExtendedWindowStyles.WS_EX_TRANSPARENT;
            NativeMethods.SetWindowLong(HWnd, NativeMethods.GWL_EXSTYLE, exStyle);

            var style = NativeMethods.GetWindowLong(HWnd, NativeMethods.GWL_STYLE);
            style |= (int)WindowStyles.WS_CAPTION | (int)WindowStyles.WS_SYSMENU;
            NativeMethods.SetWindowLong(HWnd, NativeMethods.GWL_STYLE, exStyle);

            MagnificationInitialized = NativeMethods.MagInitialize();

            if (MagnificationInitialized)
            {
                SetupMagnifier();

                Timer.Interval = TimeSpan.FromMilliseconds(NativeMethods.USER_TIMER_MINIMUM);
                Timer.Tick += Timer_Tick;
                Timer.Start();
            }
        }

        protected override void OnClosing(CancelEventArgs e)
        {
            base.OnClosing(e);

            RemoveMagnifier();
        }

        private void Timer_Tick(object sender, EventArgs e)
        {
            UpdateMaginifier();
        }


        private void SetupMagnifier()
        {
            var hInst = NativeMethods.GetModuleHandle(null);

            NativeMethods.GetClientRect(HWnd, ref MagWindowRect);

            HWndMag = NativeMethods.CreateWindow((int)ExtendedWindowStyles.WS_EX_STATICEDGE, NativeMethods.WC_MAGNIFIER,
                    "MagnificationWindow", (int)WindowStyles.WS_CHILD | (int)MagnifierStyle.MS_SHOWMAGNIFIEDCURSOR | (int)WindowStyles.WS_VISIBLE,
                    MagWindowRect.left, MagWindowRect.top, MagWindowRect.right, MagWindowRect.bottom, HWnd, IntPtr.Zero, hInst, IntPtr.Zero);

            NativeMethods.MagShowSystemCursor(false);

            if (HWndMag == IntPtr.Zero)
            {
                return;
            }

            var matrix = new Transformation(Magnification);
            NativeMethods.MagSetWindowTransform(HWndMag, ref matrix);
        }

        private void UpdateMaginifier()
        {
            if (!MagnificationInitialized || HWndMag == IntPtr.Zero)
            {
                return;
            }

            POINT mousePoint = new POINT();
            RECT sourceRect = new RECT();

            NativeMethods.GetCursorPos(ref mousePoint);

            int width = (int)((MagWindowRect.right - MagWindowRect.left) / Magnification);
            int height = (int)((MagWindowRect.bottom - MagWindowRect.top) / Magnification);

            sourceRect.left = mousePoint.x - width / 2;
            sourceRect.top = mousePoint.y - height / 2;

            NativeMethods.MagSetWindowSource(HWndMag, sourceRect);

            POINT mouse = new POINT();
            NativeMethods.GetCursorPos(ref mouse);

            NativeMethods.SetWindowPos(HWnd, NativeMethods.HWND_TOPMOST, mouse.x - (int)(magnification * width / 2), mouse.y - (int)(magnification * height / 2), width, height, 
                (int)SetWindowPosFlags.SWP_NOACTIVATE | 
                (int)SetWindowPosFlags.SWP_NOSIZE);

            NativeMethods.InvalidateRect(HWndMag, IntPtr.Zero, true);
        }

        public void RemoveMagnifier()
        {
            if (MagnificationInitialized)
            {
                NativeMethods.MagUninitialize();

                MagnificationInitialized = false;
            }
        }    
    
        // ...
   }
TontonVelu
  • 471
  • 2
  • 8
  • 21
  • I can reproduce it with the [Magnification sample](https://github.com/microsoft/Windows-classic-samples/tree/master/Samples/Magnification) in windows-classic-sample. I will confirm with the Internal engineer if it is possible to do that, and you could also open an issue on the github. – Drake Wu Jul 28 '20 at 07:36
  • Thank you, for reaching out! And thank you for getting official confirmation from the engineer. I will open an issue on GitHub as well. Please provide an update as soon as you are able to. Thanks again. – Johannes Bergman Jul 28 '20 at 11:19

1 Answers1

1

I posted this question in the Microsoft Q/A forum and got a solution that got it working.

https://learn.microsoft.com/en-us/answers/questions/54196/magnifier-control-unable-to-magnify-the-taskbar-st.html


We need to make it a Accessibility app by setting uiAcess=true in the manifest, sign the executable, and placing it in a secure location (e.g. Program Files) as described below:

  1. Set uiAccess=true in the manifest Set this option in Visual Studio by setting Linker | Manifest File | UAC Bypass UI Protection to Yes

  2. Sign the executable See https://learn.microsoft.com/en-us/previous-versions/bb756995(v=msdn.10)

  3. Place it in a secure location See https://learn.microsoft.com/en-us/windows/security/threat-protection/security-policy-settings/user-account-control-only-elevate-uiaccess-applications-that-are-installed-in-secure-locations


I placed the application in a secure location before I signed it and used the following commands to create the certificate and sign the application.

makecert /n "CN=Company, O=Company, C=SE" /r /pe /h 0 /eku "1.3.6.1.5.5.7.3.3,1.3.6.1.4.1.311.10.3.13" /e 01/01/2021 /sv Company.pvk Company.cer

Pvk2Pfx /pvk Company.pvk /pi "password" /spc Company.cer /pfx Company.pfx /po "password" /pi "password"

and finally

signtool sign /f "Company.pfx" /p "password" "application".exe

And that's it!