Announcement

Collapse
No announcement yet.

Where in my PC can I find where the Windows 10 Magnification is Located?

Collapse
X
 
  • Filter
  • Time
  • Show
Clear All
new posts

  • Where in my PC can I find where the Windows 10 Magnification is Located?

    I wrote a macro to move the cursor, click buttons and enter data into an application which I did know the Control Handles so the cursor positions were absolute pixel based. It worked perfectly on my 2K display but I'm moving to a 4K display and set the Magnification to 200% which really messed up my Macro. I know for a 1 off I could just multiply the cursor positions by 0.5 but I would prefer to make it general purpose and sense the Magnification automatically. Does anyone know where the Magnification is stored?

    Thank you

  • #2
    Howdy, Bob!

    That's a great question. When I enable magnification for my users I have a variable to keep track of status. But, when they start my app, I don't have a way of knowing if magnification is already on, or what the magnification level is.

    I'll nose around some to see what I can find

    Comment


    • #3
      Howdy, Bob!

      Reading here ..

      https://docs.microsoft.com/en-us/win...i/magapi-intro

      and here ...

      https://docs.microsoft.com/en-us/win...owsystemcursor

      ... looks promising for getting information.

      And, Jose has "magnification.inc" in his includes.

      I just haven't read enough yet to know how to use it!

      Comment


      • #4
        The monitor scaling is stored in the registry but it only appears to update when Windows restarts.
        HKEY_CURRENT_USER/Control Panel/Desktop/Window metrics/Applied DPI

        Comment


        • #5
          Howdy, Paul!

          If I exit magnification and return, it keeps the magnification levels between sessions. So, it must be kept somewhere else? I was hoping one of the API would allow retrieving it?

          Comment


          • #6
            GetScaleFactorForMonitor

            GetScaleFactorForMonitor will provide you the actual scaling.
            You may use RegisterScaleChangeEvent/UnregisterScaleChangeEvent to be notified dynamically.
            A manifest with a compatibility section is mandatory to get valid result.

            Code:
            #COMPILE EXE '#Win 10.03#
            #DIM ALL
            #INCLUDE "Win32Api.inc"
            '#INCLUDE "ShellScalingApi.inc" 'From José's API includes
            
            #RESOURCE "GetScaleFactorForMonitor.pbr" 'Need 'urn:schemas-microsoft-com:compatibility.v1'
            
            DECLARE FUNCTION GetScaleFactorForMonitor LIB "SHCORE.DLL" ALIAS "GetScaleFactorForMonitor" _
            (BYVAL hMon AS DWORD, BYREF dwScale AS LONG) AS LONG
            
            DECLARE FUNCTION RegisterScaleChangeEvent LIB "SHCORE.DLL" ALIAS "RegisterScaleChangeEvent" _
            (BYVAL hEvent AS DWORD, BYREF pdwCookie AS DWORD) AS LONG
            
            DECLARE FUNCTION UnregisterScaleChangeEvent LIB "SHCORE.DLL" ALIAS "UnregisterScaleChangeEvent" _
            (BYVAL dwCookie AS DWORD) AS LONG
            
            GLOBAL hDlg AS DWORD
            
            $AppName       = "GetScaleFactorForMonitor"
            %StaticInfo    = 101
            %ButtonDisplay = 201
            '______________________________________________________________________________
            
            THREAD FUNCTION ScaleChangeThread(BYVAL hEvent AS DWORD) AS LONG
            
             DO
               WaitForSingleObject(hEvent, %INFINITE) 'Wait for OS scale change
               PostMessage(hDlg, %WM_APP, 0, 0)
             LOOP
            
            END FUNCTION
            '_____________________________________________________________________________
            
            CALLBACK FUNCTION DlgProc
             LOCAL  hThread   AS DWORD
             LOCAL  hMonitor  AS DWORD
             STATIC hEvent    AS DWORD
             LOCAL  dwScale   AS DWORD
             STATIC dwCookie  AS DWORD
            
             SELECT CASE CBMSG
            
               CASE %WM_INITDIALOG
                 hEvent = CreateEvent (BYVAL %NULL, BYVAL 0, BYVAL 0, "ScaleEvent")
                 THREAD CREATE ScaleChangeThread(hEvent) TO hThread
                 THREAD CLOSE hThread TO hThread
                 RegisterScaleChangeEvent(hEvent, dwCookie) 'Be notified of OS scale change
                 PostMessage(hDlg, %WM_APP, 0, 0) 'First time call
            
               CASE %WM_APP
                 hMonitor = MonitorFromWindow(GetDesktopWindow(), %MONITOR_DEFAULTTOPRIMARY) 'Checking default monitor
                 GetScaleFactorForMonitor(hMonitor, dwScale)
                 CONTROL SET TEXT hDlg, %StaticInfo, "Scale is" & STR$(dwScale) & "% at " & TIME$
            
               CASE %WM_COMMAND
                 SELECT CASE CBCTL
                   CASE %ButtonDisplay
                     IF CBCTLMSG = %BN_CLICKED OR CBCTLMSG = 1 THEN
                       SHELL("rundll32.exe shell32.dll,Control_RunDLL desk.cpl")
                     END IF
                 END SELECT
            
               CASE %WM_DESTROY
                 UnregisterScaleChangeEvent(dwCookie)
                 CloseHandle(hEvent)
            
              END SELECT
            
            END FUNCTION
            '______________________________________________________________________________
            
            FUNCTION PBMAIN()
             LOCAL hIcon AS DWORD
            
             DIALOG FONT "Segoe UI", 9
             DIALOG NEW PIXELS, %HWND_DESKTOP, $AppName, , , 400, 100, _
             %WS_CAPTION OR %WS_MINIMIZEBOX OR %WS_SYSMENU, 0 TO hDlg
            
             CONTROL ADD LABEL, hDlg, %StaticInfo, "Scale %", 10, 10, 390, 20
            
             CONTROL ADD BUTTON, hDlg, %ButtonDisplay, "Change display scale", 10, 65, 200, 30
            
             hIcon = ExtractIcon(GETMODULEHANDLE(""), "Shell32.dll", 294) 'o
             SetClassLong(hDlg, %GCL_HICON, hIcon)
            
             DIALOG SHOW MODAL hDlg CALL DlgProc
            
             DestroyIcon(hIcon)
            
            END FUNCTION
            '______________________________________________________________________________
            '
            Here is a manifest embedded in a resource file named GetScaleFactorForMonitor.rc.
            Compile it to GetScaleFactorForMonitor.pbr
            Code:
            #include "resource.h"
            
            #define IDR_MANIFEST 1
            #define RT_MANIFEST 24
            
            IDR_MANIFEST RT_MANIFEST MOVEABLE PURE
            {
             "<assembly xmlns='urn:schemas-microsoft-com:asm.v1' manifestVersion='1.0'>
            
               <description>Windows Shell</description>
            
               <!-- Compatibility section for Program Compatibility Assistant (PCA) -->
               <compatibility xmlns='urn:schemas-microsoft-com:compatibility.v1'>
                 <application>
                   <supportedOS Id='{e2011457-1546-43c5-a5fe-008deee3d3f0}'/>
                   <supportedOS Id='{35138b9a-5d96-4fbd-8e2d-a2440225f93a}'/>
                   <supportedOS Id='{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}'/>
                   <supportedOS Id='{1f676c76-80e1-4239-95bb-83d0f6d0da78}'/>
                   <supportedOS Id='{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}'/>
                 </application>
                 // <!-- {e2011457-1546-43c5-a5fe-008deee3d3f0} Windows Vista (6.0) -->
                 // <!-- {35138b9a-5d96-4fbd-8e2d-a2440225f93a} Windows 7 (6.1) -->
                 // <!-- {4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38} Windows 8 (6.2) -->
                 // <!-- {1f676c76-80e1-4239-95bb-83d0f6d0da78} Windows 8.1 (6.3) Needed to avoid GetVersionEx report 6.2 -->
                 // <!-- {8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a} Windows 10.0 (10.0) Needed to avoid GetVersionEx report 6.2 -->
               </compatibility>
            
               <!-- Common controls section -->
               <dependency>
                 <dependentAssembly>
                   <assemblyIdentity
                     type='win32'
                     name='Microsoft.Windows.Common-Controls'
                     version='6.0.0.0'
                     processorArchitecture='x86'
                     publicKeyToken='6595b64144ccf1df'
                     language='*'
                   />
                 </dependentAssembly>
               </dependency>
            
               <!-- DpiAware and long path section -->
               <asmv3:application xmlns:asmv3='urn:schemas-microsoft-com:asm.v3'>
                 <asmv3:windowsSettings xmlns='http:\x2F\x2Fschemas.microsoft.com/SMI/2005/WindowsSettings'>
                   <dpiAware>true</dpiAware>
                   <Path:LongPathAware>false</Path:LongPathAware>
                 </asmv3:windowsSettings>
               </asmv3:application>
            
               <!-- RunAs section -->
               <asmv3:trustInfo xmlns:asmv3='urn:schemas-microsoft-com:asm.v3'>
                 <asmv3:security>
                   <asmv3:requestedPrivileges>
                     <asmv3:requestedExecutionLevel
                       level='asInvoker'
                       uiAccess='false'
                     />
                   </asmv3:requestedPrivileges>
                 </asmv3:security>
               </asmv3:trustInfo>
            
             </assembly>"
            }
            //
            Last edited by Pierre Bellisle; 13 Sep 2021, 06:22 PM.

            Comment


            • #7
              Thanks for all the info guys. With my 2K Monitor and 100% Magnification I thought I was good but maybe with your info I can get the program working with my 4K monitor and 200% Magnification. Working.

              Thanks very much!

              Bob

              Comment


              • #8
                GetScaleFactorForMonitor

                Here is a version for multi monitor using the same resource manifest as above.
                Code:
                #COMPILE EXE '#Win 10.03#
                #DIM ALL
                #INCLUDE "Win32Api.inc"
                '#INCLUDE "ShellScalingApi.inc" 'From José's API includes
                
                #RESOURCE "GetScaleFactorForMonitor.pbr" 'Need 'urn:schemas-microsoft-com:compatibility.v1'
                
                DECLARE FUNCTION GetScaleFactorForMonitor LIB "SHCORE.DLL" ALIAS "GetScaleFactorForMonitor" _
                (BYVAL hMon AS DWORD, BYREF dwScale AS LONG) AS LONG
                
                DECLARE FUNCTION RegisterScaleChangeEvent LIB "SHCORE.DLL" ALIAS "RegisterScaleChangeEvent" _
                (BYVAL hEvent AS DWORD, BYREF pdwCookie AS DWORD) AS LONG
                
                DECLARE FUNCTION UnregisterScaleChangeEvent LIB "SHCORE.DLL" ALIAS "UnregisterScaleChangeEvent" _
                (BYVAL dwCookie AS DWORD) AS LONG
                
                GLOBAL hDlg  AS DWORD
                GLOBAL sInfo AS STRING
                
                $AppName       = "GetScaleFactorForMonitor"
                %EditInfo      = 101
                %ButtonDisplay = 201
                '______________________________________________________________________________
                
                FUNCTION MonitorEnum(BYVAL hMonitor AS DWORD, BYVAL hdcMonitor AS DWORD, _
                                     BYREF rectMonitor AS RECT, hMonitorArray() AS DWORD) AS LONG
                 LOCAL MonitorInf AS MONITORINFOEX
                 LOCAL dwScale    AS DWORD
                
                 MonitorInf.cbSize = SIZEOF(MONITORINFOEX)
                 GetMonitorInfo(hMonitor, BYVAL VARPTR(MonitorInf))
                
                 sInfo &= "Device:   " & MonitorInf.szDevice & _
                          IIF$(MonitorInf.dwFlags = %MONITORINFOF_PRIMARY, " (Primary monitor)", "") & $CRLF & _
                          "Monitor:  " & FORMAT$(MonitorInf.rcMonitor.nRight  - MonitorInf.rcMonitor.nLeft) & " by " & _
                                         FORMAT$(MonitorInf.rcMonitor.nBottom - MonitorInf.rcMonitor.nTop) & _
                          " (LRTB: " &   FORMAT$(MonitorInf.rcMonitor.nLeft) & " " & FORMAT$(MonitorInf.rcMonitor.nRight) & " " &  _
                                         FORMAT$(MonitorInf.rcMonitor.nTop)  & " " & FORMAT$(MonitorInf.rcMonitor.nBottom) & ")" & $CRLF & _
                          "WorkArea: " & FORMAT$(MonitorInf.rcWork.nRight  - MonitorInf.rcWork.nLeft) & " by " & _
                                         FORMAT$(MonitorInf.rcWork.nBottom - MonitorInf.rcWork.nTop) & _
                          " (LRTB: " &   FORMAT$(MonitorInf.rcWork.nLeft) & " " &  FORMAT$(MonitorInf.rcWork.nRight) & " " &  _
                                         FORMAT$(MonitorInf.rcWork.nTop)  & " " &  FORMAT$(MonitorInf.rcWork.nBottom) & ")" & $CRLF
                
                 GetScaleFactorForMonitor(hMonitor, dwScale)
                 sInfo &= "Scale is" & STR$(dwScale) & "%" & $CRLF & $CRLF
                 
                 FUNCTION = %TRUE 'Continue enumeration until no more monitors
                
                END FUNCTION
                '_____________________________________________________________________________
                
                THREAD FUNCTION ScaleChangeThread(BYVAL hEvent AS DWORD) AS LONG
                
                 DO
                   WaitForSingleObject(hEvent, %INFINITE) 'Wait for OS scale change
                   PostMessage(hDlg, %WM_APP, 0, 0)
                 LOOP
                
                END FUNCTION
                '_____________________________________________________________________________
                
                CALLBACK FUNCTION DlgProc
                 LOCAL  hThread   AS DWORD
                 STATIC hEvent    AS DWORD
                 STATIC dwCookie  AS DWORD
                 LOCAL  dwScale   AS DWORD
                
                 SELECT CASE CBMSG
                
                   CASE %WM_INITDIALOG
                     hEvent = CreateEvent (BYVAL %NULL, BYVAL 0, BYVAL 0, "ScaleEvent")
                     THREAD CREATE ScaleChangeThread(hEvent) TO hThread
                     THREAD CLOSE hThread TO hThread
                     RegisterScaleChangeEvent(hEvent, dwCookie) 'Be notified of OS scale change
                     PostMessage(hDlg, %WM_APP, 0, 0) 'First time call
                
                   CASE %WM_APP
                     sInfo = ""
                     EnumDisplayMonitors(BYVAL %NULL, BYVAL %NULL, BYVAL CODEPTR(MonitorEnum), 0) 'BYVAL VARPTR(hMonitorArray()))
                     CONTROL SET TEXT hDlg, %EditInfo, sInfo
                
                   CASE %WM_COMMAND
                     SELECT CASE CBCTL
                       CASE %ButtonDisplay
                         IF CBCTLMSG = %BN_CLICKED OR CBCTLMSG = 1 THEN
                           SHELL("rundll32.exe shell32.dll,Control_RunDLL desk.cpl")
                         END IF
                     END SELECT
                
                   CASE %WM_WINDOWPOSCHANGED
                     'App window can be moved between monitors.
                     GetScaleFactorForMonitor(MonitorFromWindow(hDlg, %MONITOR_DEFAULTTONEAREST), dwScale)
                     SetWindowText(hDlg, "Dialog is now" & STR$(dwScale) & "%")
                
                   CASE %WM_DESTROY
                     UnregisterScaleChangeEvent(dwCookie)
                     CloseHandle(hEvent)
                
                  END SELECT
                
                END FUNCTION
                '______________________________________________________________________________
                
                FUNCTION PBMAIN()
                 LOCAL hIcon AS DWORD
                
                 DIALOG FONT "Segoe UI", 9
                 DIALOG NEW PIXELS, %HWND_DESKTOP, $AppName, , , 400, 300, _
                 %WS_CAPTION OR %WS_MINIMIZEBOX OR %WS_SYSMENU, 0 TO hDlg
                
                 CONTROL ADD TEXTBOX, hDlg, %EditInfo, "Scale info", 10, 10, 390, 240, _
                 %WS_TABSTOP OR %WS_VSCROLL OR %ES_MULTILINE OR %ES_WANTRETURN, %WS_EX_CLIENTEDGE
                
                 CONTROL ADD BUTTON, hDlg, %ButtonDisplay, "Change display scale", 10, 260, 200, 30
                
                 hIcon = ExtractIcon(GETMODULEHANDLE(""), "Shell32.dll", 294) 'o
                 SetClassLong(hDlg, %GCL_HICON, hIcon)
                
                 DIALOG SHOW MODAL hDlg CALL DlgProc
                
                 DestroyIcon(hIcon)
                
                END FUNCTION
                '______________________________________________________________________________
                '
                Last edited by Pierre Bellisle; 13 Sep 2021, 04:21 PM.

                Comment


                • #9
                  Peter,

                  I was away from PowerBasic for three years while I was taking care of my wife who had ALS and also since I am an octogenarian I decided not to upgrade to version 10 so I am running version 9.05. I changed your version 10 program just enough to compile in 9.05 which was just change the FUNCTION Declares from IMPORT to LIB which allows a 9.05 compile but I get funny numbers. On my 2K 100% machine it looks good but on my 4K 200% machine - not so good. Do you see anything that should also be changed?

                  Thanks much,


                  Bob Click image for larger version

Name:	Peter 2K &amp; 4K.png
Views:	109
Size:	116.5 KB
ID:	810838

                  Comment


                  • #10
                    One may get erroneous result like that if the manifest is not there.
                    First thing would be to double check that the mandatory manifest
                    embedded in the rc file is there with the "Compatibility section" as shown above in my first post.

                    Comment


                    • #11
                      Click image for larger version

Name:	Peter 4K.png
Views:	92
Size:	19.2 KB
ID:	810842
                      Mystery solved. I had missed the very last line in the RC (")") - just sloppy. Thank you very much Peter!

                      \

                      Comment


                      • #12
                        Great!

                        Comment


                        • #13
                          Hi Pierre

                          refering to your post #6
                          I tried compiling GetScaleFactorForMonitor.rc to get GetScaleFactorForMonitor.pbr but got GetScaleFactorForMonitor.res instead

                          And in the main program when I changed the name to GetScaleFactorForMonitor.res from GetScaleFactorForMonitor.pbr
                          the main program cannot compile and gives the error

                          Error 478 in C:\PB tst2\Monitor scalefactor\Monitor scaleFactor.bas(10:001): Resource file error
                          Line 10: #RESOURCE "GetScaleFactorForMonitor.res" 'Need 'urn:schemas-microsoft-com:compatibility.v1'



                          Changing back to GetScaleFactorForMonitor.pbr also give the same error message

                          What's the problem as I'm using PB Win 10.03 ?




                          Comment


                          • #14
                            In that event, to work with a .res file, just change
                            #RESOURCE "GetScaleFactorForMonitor.pbr"
                            to
                            #RESOURCE RES, "GetScaleFactorForMonitor.RES"

                            Also, in the PowerBASIC editor, you got the menu OPTIONS / Compiler / Create a .PBR when compiling .RC files

                            Comment


                            • #15
                              Thanks Pierre

                              Comment

                              Working...
                              X