Jump to content

making your compiled application DPI Aware


Recommended Posts

Since this thread is getting long, I thought I'd copy all the relevant information to the 1st post.

Three different types of DPI Aware'ness are made available from Microsoft.
1. System Aware (introduced with Windows Vista)
2. Per Monitor Aware (Introduced with Windows 8.1)
3. Per Monitor Aware V2 (Introduced with Windows 10 1703)

Method #1 - Programmatically  - Only available for Windows 8.1 and 10

; For values available to Windows 10 users - https://docs.microsoft.com/en-gb/windows/win32/hidpi/dpi-awareness-context

If @OSVersion = 'WIN_10' Then DllCall("User32.dll", "bool", "SetProcessDpiAwarenessContext" , "HWND", "DPI_AWARENESS_CONTEXT" -2)
If @OSVersion = 'WIN_81' Then DllCall("User32.dll", "bool", "SetProcessDPIAware")

;  *** Microsoft warns that these entries need to be executed before the GUI is created ***
;This is the only reason they recommend using the Manifest method over the programmatic method

When using the above code, Windows 10 and 8.1 will recognize your compiled app as DPI System Aware.

 

Method #2 - using Manifest entries - Available for all Windows starting with Vista, up to current and future releases of Windows.
Using #AutoIt3Wrapper_Res_HiDpi=Y will set your compiled app as DPI System Aware (Win Vista, 7, 8.1, 10).

 For Windows 8.1, using the Manifest method is the only way to have Per Monitor Aware.
Follow this link to learn how to create Per Monitor Aware and Per Monitor Aware V2 apps for Windows 10.  Learn how here
      *** This is the Microsoft recommended method of creating a DPI Aware application ***

 

*** If you choose either method above, you will still need to deal with the GUI itself and all of its Controls. ***
Being DPI Aware only deals with text. The simplest method to achieve this is to adapt the code below into your script.

Global $iScale = RegRead("HKCU\Control Panel\Desktop\WindowMetrics", "AppliedDPI") / 96
GUICreate("DPI test", 200 * $iScale, 100 * $iScale)
GUICtrlCreateButton("Ima Button", 35 * $iScale, 115 * $iScale, 55 * $iScale, 21 * $iScale)

; For reference, I have a single App with 579 occurances of $iScale
; Also know; I've had to make some small x,y adjustments to keep the GUI looking good but nothing drastic.
; Be sure to test your compiled app at 125% and at 200%. This is how I found small descrepancies requiring x,y adjustments.

more importantly, this registry value can be had, programmatically and in my opinion, more efficiently
With 4k monitors becoming a norm, this should set you well on your way to creating a DPI Aware applications that looks good on any system.

Edited by Shark007
Link to post
Share on other sites
  • Replies 60
  • Created
  • Last Reply

Top Posters In This Topic

Top Posters In This Topic

Popular Posts

Since this thread is getting long, I thought I'd copy all the relevant information to the 1st post. Three different types of DPI Aware'ness are made available from Microsoft. 1. System Aware (i

System will not resize GUI and controls according to DPI scaling. You must do this manually. For example ; current value of primary monitor DPI is stored in the registry: ; HKCU\Control

Maybe this will help. As the page is in German, use any translator -> https://autoit.de/index.php?thread/86505-guiscaler-guis-automatisch-zur-dpi-skalieren-lassen-windows-7-und-windows-10-per/

Posted Images

To followup further, I have even tried editing  AutoIt3Wrapper.au3 to place the following into the manifest

<application xmlns="urn:schemas-microsoft-com:asm.v3">
    <windowsSettings>
        <dpiAwareness xmlns="http://schemas.microsoft.com/SMI/2016/WindowsSettings">PerMonitorV2</dpiAwareness>
        <dpiAware>true</dpiAware>
    </windowsSettings>
</application>
</assembly>

but still no joy. It does the same as before I edited it.

Link to post
Share on other sites

I know you won't like it, but to resolve all those problems, change resolution to 1600 x 900 or 1440 x 900 depending how it is managed by the OS. And put Windows scale at 100%. Problem solved, at least for many of us...

Link to post
Share on other sites
20 hours ago, Shark007 said:

It resizes the text OK but not the GUI.

System will not resize GUI and controls according to DPI scaling. You must do this manually. For example

; current value of primary monitor DPI is stored in the registry:
; HKCU\Control Panel\Desktop\WindowMetrics, AppliedDPI
; need to relogin after DPI changed to update this value

$Scale = RegRead("HKCU\Control Panel\Desktop\WindowMetrics", "AppliedDPI") / 96

DllCall("User32.dll", "bool", "SetProcessDPIAware")

GUICreate("DPI test", 200 * $Scale, 100 * $Scale)
GUICtrlCreateButton("test button text", 10 * $Scale, 10 * $Scale, 80 * $Scale, 25 * $Scale)
GUICtrlCreateCombo("test combo text", 10 * $Scale, 40 * $Scale, 100 * $Scale, 25 * $Scale)
GUICtrlCreateLabel("test label text", 10 * $Scale, 70 * $Scale, 70 * $Scale, 25 * $Scale)
GUISetState()
Do
Until GUIGetMsg() = -3

 

Edited by InnI
Link to post
Share on other sites

Please don't send me any personal message and ask for support! I will not reply!

Selection of finest graphical examples at Codepen.io

The own fart smells best!
Her 'sikim hıyar' diyene bir avuç tuz alıp koşma!
¯\_(ツ)_/¯  ٩(●̮̮̃•̃)۶ ٩(-̮̮̃-̃)۶ૐ

Link to post
Share on other sites

After much testing, I ended up using using the Microsoft recommended manifest entries which are applied properly using
#AutoIt3Wrapper_Res_HiDpi=Y resulting in the compiled app being recognized as DPI System Aware.
Then I combined this with similar coding as depicted below to adjust the entire GUI and all of its controls.

$Scale = RegRead("HKCU\Control Panel\Desktop\WindowMetrics", "AppliedDPI") / 96
GUICreate("DPI test", 200 * $Scale, 100 * $Scale)

Everything in my app(s) is functioning well (with some slight x,y adjustments to keep it beautiful) in 32 and 64bit compiles.

Thanks to all those offering helpful advice!

Edited by Shark007
code typo
Link to post
Share on other sites
22 hours ago, Shark007 said:

So it seems I just needed more complete syntax.

For Windows 10... working code

If @OSVersion = 'WIN_10' Then DllCall("User32.dll", "bool", "SetProcessDpiAwarenessContext" , "HWND", "DPI_AWARENESS_CONTEXT" -2)

With the available values documented HERE

 

Just to complete my initial request of solving DPI Awareness programmatically, even though I decided t to use the manifest method instead,

below is working code for Windows 8.1

If @OSVersion = 'WIN_81' Then DllCall("User32.dll", "bool", "SetProcessDPIAware")

The above code will make your compiled app DPI System Aware on Windows 8.1 systems. It does not have any parameters like the Windows 10 version has.

Link to post
Share on other sites

Can you please test this code on different OS builds?

;Coded by UEZ build 2019-08-05 beta

#AutoIt3Wrapper_Res_HiDpi=Y

#include <Array.au3>
#include <GUIConstantsEx.au3>
#include <GDIPlus.au3>
#include <WinAPIGdiDC.au3>
#include <WinAPISysWin.au3>

_GDIPlus_Startup()

; enum _PROCESS_DPI_AWARENESS -> https://msdn.microsoft.com/en-us/library/windows/desktop/dn280512(v=vs.85).aspx
Global Enum $DPI_AWARENESS_INVALID = -1, $PROCESS_DPI_UNAWARE = 0, $PROCESS_SYSTEM_DPI_AWARE, $PROCESS_PER_MONITOR_DPI_AWARE

Global Enum $Context_UnawareGdiScaled = -5, $Context_PerMonitorAwareV2, $Context_PerMonitorAware, $Context_SystemAware, $Context_Unaware

; enum _MONITOR_DPI_TYPE
Global Enum $MDT_EFFECTIVE_DPI = 0, $MDT_ANGULAR_DPI, $MDT_RAW_DPI
Global Const $MDT_DEFAULT = $MDT_EFFECTIVE_DPI

Global Const $WM_DPICHANGED = 0x02E0

Global $dpiScaledX, $dpiScaledY, $aCtrlFS[5][2]

If Not @Compiled Then _WinAPI_SetDPIAwareness()

Example1()

_GDIPlus_Shutdown()

Func Example1() ;example by alpines
    Local Const $GUI_CLIENT_WIDTH = 314
    Local Const $GUI_CLIENT_HEIGHT = 130

    Local $hGUI = GUICreate("Example 1", $GUI_CLIENT_WIDTH, $GUI_CLIENT_HEIGHT, -1, -1)
    GUISetFont(12, 400, 0, "Times New Roman")

    $aCtrlFS[0][0] = GUICtrlCreateLabel("Label1", 16, 16, 36, 21)
    $aCtrlFS[0][1] = 10
    GUICtrlSetFont(-1, $aCtrlFS[0][1], 400, 0, "Times New Roman", 5)
    GUICtrlSetBkColor(-1, 0x3399FF)
    GUICtrlSetResizing(-1, $GUI_DOCKAUTO)

    $aCtrlFS[1][0] = GUICtrlCreateLabel("Label2", 64, 16, 36, 21)
    $aCtrlFS[1][1] = 10
    GUICtrlSetFont(-1, $aCtrlFS[1][1], 400, 0, "Times New Roman", 5)
    GUICtrlSetBkColor(-1, 0x3399FF)
    GUICtrlSetResizing(-1, $GUI_DOCKAUTO)

    $aCtrlFS[2][0] = GUICtrlCreateLabel("Label3", 112, 16, 36, 21)
    $aCtrlFS[2][1] = 10
    GUICtrlSetFont(-1, $aCtrlFS[2][1], 400, 0, "Times New Roman", 5)
    GUICtrlSetBkColor(-1, 0x3399FF)
    GUICtrlSetResizing(-1, $GUI_DOCKAUTO)

    $aCtrlFS[3][0] = GUICtrlCreateInput("Input1", 160, 16, 137, 21)
    $aCtrlFS[3][1] = 10
    GUICtrlSetFont(-1, $aCtrlFS[3][1], 400, 0, "Times New Roman", 5)
    GUICtrlSetResizing(-1, $GUI_DOCKAUTO)

    $aCtrlFS[4][0] = GUICtrlCreateButton("Close", 16, 48, 283, 65)
    $aCtrlFS[4][1] = 10
    GUICtrlSetFont(-1, $aCtrlFS[4][1], 400, 0, "Times New Roman", 5)
    GUICtrlSetResizing(-1, $GUI_DOCKAUTO)

    GUISetState(@SW_SHOW, $hGUI)
    GUIRegisterMsg($WM_DPICHANGED, "WM_DPICHANGED")

    While True
        Switch GUIGetMsg()
            Case $GUI_EVENT_CLOSE, $aCtrlFS[4][0]
                GUIDelete($hGUI)
                ExitLoop
        EndSwitch
    WEnd
EndFunc   ;==>Example1

Func WM_DPICHANGED($hWnd, $iMsg, $wParam, $lParam)
    Local $tRECT = DllStructCreate($tagRECT, $lParam)
    Local $iDPIX = _WinAPI_LoWord($wParam), $iDPIY = _WinAPI_HiWord($wParam)
    $dpiScaledX = $iDPIX / 96
    $dpiScaledY = $iDPIY / 96
    Local $iW = $tRECT.right - $tRECT.left, $iH = $tRECT.bottom - $tRECT.top
    Local $aWPos = WinGetPos($hWnd)
    _WinAPI_SetWindowPos($hWnd, 0, $aWPos[0], $aWPos[1], $iW, $iH, BitOR($SWP_NOZORDER, $SWP_NOACTIVATE))
    UpdateControlFontSize()
EndFunc   ;==>WM_DPICHANGED

Func UpdateControlFontSize()
    Local $i
    For $i = 0 To UBound($aCtrlFS) - 1
        GUICtrlSetFont($aCtrlFS[$i][0], $aCtrlFS[$i][1] * $dpiScaledX)
    Next
EndFunc   ;==>UpdateControlFontSize

Func _GDIPlus_GraphicsGetDPIRatio($iDPIDef = 96)
    Local $hGfx = _GDIPlus_GraphicsCreateFromHWND(0)
    If @error Then Return SetError(1, @extended, 0)
    Local $aResult = DllCall($__g_hGDIPDll, "int", "GdipGetDpiX", "handle", $hGfx, "float*", 0)
    If @error Then Return SetError(2, @extended, 0)
    Local $iDPI = $aResult[2]
    _GDIPlus_GraphicsDispose($hGfx)
    Local $aResults[2] = [$iDPIDef / $iDPI, $iDPI / $iDPIDef]
    Return $aResults
EndFunc   ;==>_GDIPlus_GraphicsGetDPIRatio

Func _WinAPI_GetDpiForMonitor($dpiType = $MDT_DEFAULT, $iDPIDef = 96)
    Local $aMonitors = _WinAPI_EnumDisplayMonitors()
    Local $x, $y
    Local $aRet = DllCall("Shcore.dll", "long", "GetDpiForMonitor", "long", $aMonitors[1][0], "int", $dpiType, "uint*", $x, "uint*", $y)
    If @error Or Not IsArray($aRet) Then Return SetError(1, 0, 0)
    Local $aDPI[2] = [$iDPIDef / $aRet[3], $aRet[3] / $iDPIDef]
    Return $aDPI
EndFunc   ;==>_WinAPI_GetDpiForMonitor

Func _WinAPI_SetDPIAwareness($hGUI = 0)
    Switch @OSBuild
        Case 6000 To 9199
            If Not DllCall("user32.dll", "bool", "SetProcessDPIAware") Then Return SetError(1, 0, 0)
            Return 1
        Case 9200 To 13999
            _WinAPI_SetProcessDpiAwareness($PROCESS_PER_MONITOR_DPI_AWARE)
            If @error Then Return SetError(2, 0, 0)
            Return 1
        Case @OSBuild > 13999
            #cs
                Context_Unaware = ((DPI_AWARENESS_CONTEXT)(-1)),
                Context_SystemAware = ((DPI_AWARENESS_CONTEXT)(-2)),
                Context_PerMonitorAware = ((DPI_AWARENESS_CONTEXT)(-3)),
                Context_PerMonitorAwareV2 = ((DPI_AWARENESS_CONTEXT)(-4)),
                Context_UnawareGdiScaled = ((DPI_AWARENESS_CONTEXT)(-5))
            #ce
            _WinAPI_SetProcessDpiAwarenessContext($Context_PerMonitorAwareV2, $hGUI)
            If @error Then Return SetError(3, @error, 0)
            Return 1
    EndSwitch
    Return -1
EndFunc   ;==>_WinAPI_SetDPIAwareness

Func _WinAPI_SetProcessDpiAwareness($DPIAware) ;https://docs.microsoft.com/en-us/windows/desktop/api/shellscalingapi/nf-shellscalingapi-setprocessdpiawareness
    Local $aResult = DllCall("Shcore.dll", "long", "SetProcessDpiAwareness", "int", $DPIAware)
    If @error Then Return SetError(1, 0, 0)
    Return 1
EndFunc   ;==>_WinAPI_SetProcessDpiAwareness

Func _WinAPI_SetProcessDpiAwarenessContext($DPIAwareContext = $Context_PerMonitorAware, $hGUI = 0, $iMode = 3) ;https://docs.microsoft.com/en-us/windows/desktop/api/winuser/nf-winuser-setprocessdpiawarenesscontext
    $DPIAwareContext = ($DPIAwareContext < -5) ? -5 : ($DPIAwareContext > -1) ? -1 : $DPIAwareContext
    $iMode = ($iMode < 1) ? 1 : ($iMode > 3) ? 3 : $iMode
    Switch $iMode
        Case 1
            Local $hDC = _WinAPI_GetDC($hGUI)
            Local $aResult1 = DllCall("user32.dll", "int", "GetDpiFromDpiAwarenessContext", "ptr", $hDC)
            If @error Or Not IsArray($aResult1) Then Return SetError(11, 0, 0)
            _WinAPI_ReleaseDC(0, $hDC)
            Local $aResult = DllCall("user32.dll", "Bool", "SetProcessDpiAwarenessContext", "int", $aResult1[0] + $DPIAwareContext)
            If @error Or Not IsArray($aResult) Then Return SetError(12, 0, 0)
        Case 2
;~          If Not $hGUI Then $hGUI = WinGetHandle(AutoItWinGetTitle())
            Local $aResult2 = DllCall("user32.dll", "int", "GetWindowDpiAwarenessContext", "ptr", $hGUI)
            If @error Or Not IsArray($aResult2) Then Return SetError(21, 0, 0)
            Local $aResult = DllCall("user32.dll", "Bool", "SetProcessDpiAwarenessContext", "int", $aResult2[0] + $DPIAwareContext)
            If @error Or Not IsArray($aResult) Then Return SetError(22, 0, 0)
        Case 3
            Local $aResult31 = DllCall("user32.dll", "ptr", "GetThreadDpiAwarenessContext")
            If @error Or Not IsArray($aResult31) Then Return SetError(31, 0, 0)
            Local $aResult32 = DllCall("user32.dll", "int", "GetAwarenessFromDpiAwarenessContext", "ptr", $aResult31[0])
            If @error Or Not IsArray($aResult32) Then Return SetError(32, 0, 0)
            Local $aResult = DllCall("user32.dll", "Bool", "SetThreadDpiAwarenessContext", "int", $aResult32[0] + $DPIAwareContext)
            If @error Or Not IsArray($aResult) Then Return SetError(33, 0, 0)
    EndSwitch

    Return 1
EndFunc   ;==>_WinAPI_SetProcessDpiAwarenessContext

Does it work properly?

 

Here the manifest I used:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0" xmlns:asmv3="urn:schemas-microsoft-com:asm.v3" >

	<!-- Identify the application security requirements. -->
	<trustInfo xmlns="urn:schemas-microsoft-com:asm.v2">
		<security>
			<requestedPrivileges>
				<requestedExecutionLevel
 					level="asInvoker"
					uiAccess="false"
				/>
			</requestedPrivileges>
		</security>
	</trustInfo>

	<!-- Identify the application dependencies. -->
	<dependency>
		<dependentAssembly>
			<assemblyIdentity
				type="win32"
				name="Microsoft.Windows.Common-Controls"
				version="6.0.0.0"
				language="*"
				processorArchitecture="*"
				publicKeyToken="6595b64144ccf1df"
			/>
		</dependentAssembly>
	</dependency>

	<asmv3:application>
		<asmv3:windowsSettings xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">
		      <dpiAware>true/pm</dpiAware>
		</asmv3:windowsSettings>
		<asmv3:windowsSettings xmlns="https://schemas.microsoft.com/SMI/2016/WindowsSettings">
		      <dpiAwareness>PerMonitorV2, system</dpiAwareness>
		</asmv3:windowsSettings>
		<asmv3:windowsSettings xmlns="https://schemas.microsoft.com/SMI/2017/WindowsSettings">
		      <gdiScaling>true</gdiScaling>
		</asmv3:windowsSettings>
	</asmv3:application>

	<compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
		<application>
			<!--The ID below indicates application support for Windows Vista -->
			<supportedOS Id="{e2011457-1546-43c5-a5fe-008deee3d3f0}"/>
			<!--The ID below indicates application support for Windows 7 -->
			<supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}"/>
			<!--The ID below indicates application support for Windows 8 -->
			<supportedOS Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}"/>
			<!--The ID below indicates application support for Windows 8.1 -->
			<supportedOS Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}"/>
			<!--The ID below indicates application support for Windows 10 -->
			<supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}"/>
		</application>
	</compatibility>
</assembly>

 

Edited by UEZ

Please don't send me any personal message and ask for support! I will not reply!

Selection of finest graphical examples at Codepen.io

The own fart smells best!
Her 'sikim hıyar' diyene bir avuç tuz alıp koşma!
¯\_(ツ)_/¯  ٩(●̮̮̃•̃)۶ ٩(-̮̮̃-̃)۶ૐ

Link to post
Share on other sites

UEZ, the code does not compile. I get several failures of undefined functions. (and this was before my morning coffee!)

this is what happens before coffee! It was not a complete copy/paste of the code causing the failures. I'll get back to you later after testing of diff systems.

 

To toss some credit in your direction, I am using some code that originated with you and was later modified by mLipok and then by me.
EDIT... and streamlined further by UEZ!  (and then some more editing by me)

I use it to replace the reg query, 

$iScale = RegRead("HKCU\Control Panel\Desktop\WindowMetrics", "AppliedDPI") /96
Func DPIRatio()
    _GDIPlus_Startup()
    Local $hGfx = _GDIPlus_GraphicsCreateFromHWND(0)
    If @error Then Return SetError(1, @extended, 0)
    Local $aResult = DllCall($__g_hGDIPDll, "int", "GdipGetDpiX", "handle", $hGfx, "float*", 0)
    If @error Then Return SetError(2, @extended, 0)
    _GDIPlus_GraphicsDispose($hGfx)
    _GDIPlus_Shutdown()
    Return $aResult[2] / 96
EndFunc   ;==>DPIRatio

$iScale = DPIRatio()

In my testing, the Return'd value is the same as the value in the RegRead. I've tested this on Windows 7 , 8.1 and 10.

Edited by Shark007
Link to post
Share on other sites

UEZ, results on Diff systems.

Windows 7, other than my eyes, I cannot test for DPI Awareness. On Windows 8.1 and Windows 10, it tested as DPI System Aware

Windows 7 - 125% scaling

Windows7 - 125% scaling.jpg

Windows 8.1 - 150% scaling

Windows8 - 150% scaling- DPI System aware.jpg

Windows 10 - 200% scaling

Windows10 - 200% scaling - DPI System aware.jpg

Edited by Shark007
Link to post
Share on other sites

@Shark007 Thanks for testing but that's odd. On my Win10 v1803 b17134 it works as expected on my 3 screens whereas I set the right one (not primary) to 150%.

 

Please don't send me any personal message and ask for support! I will not reply!

Selection of finest graphical examples at Codepen.io

The own fart smells best!
Her 'sikim hıyar' diyene bir avuç tuz alıp koşma!
¯\_(ツ)_/¯  ٩(●̮̮̃•̃)۶ ٩(-̮̮̃-̃)۶ૐ

Link to post
Share on other sites

@Shark007 Can you test the compiled code from attached file please? It it the same code as above but I've modified the manifest which will be created by AutoIt3Wrapper.exe. 

Thx.

 

Edited by UEZ

Please don't send me any personal message and ask for support! I will not reply!

Selection of finest graphical examples at Codepen.io

The own fart smells best!
Her 'sikim hıyar' diyene bir avuç tuz alıp koşma!
¯\_(ツ)_/¯  ٩(●̮̮̃•̃)۶ ٩(-̮̮̃-̃)۶ૐ

Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
  • Recently Browsing   0 members

    No registered users viewing this page.

  • Similar Content

    • By Jowy
      Hello dears,
      I'm trying to write a script in AutoIT but, I have issue in DPI. I'm basically a Lead Software Developer and I use AutoIT from time to time. I have an ERP Launcher that should work on all machines starting by Windows 7, Windows 8.x , Windows 10, Windows Server 2003/2008/2012.
      When I was searching in AutoIT forum, I could see previously this " Writing DPI Awareness App - workaround" in the signature of Mr. @mLipok,, but clicking on the link, => page not found.
      Do you have any new link or something that you can share with me ? I'm using macbook pro with retina display and VMware machines: Windows 10 and Server 2012 as development machines, but both of them they have 200% scaling and they have AutoIT installed. In this case, when I use Koda (blurry font for sure), I have the controls as I want, and application is working fine, but also blurry font, until it is used on 96 DPI machine.
      Now, in windows 10, with DPI System Enhanced feature in the compatibility tab, the application running on 200% scaling is excellent visual like it's running on 96 DPI without touching my code and without doing anything, but no all clients they have windows 10. It seems Microsoft worked a lot on the new feature. But for other machines like windows 7/8/2012, the font is blurry if the clients have scaling above 100% (more than 96 DPI). I know how to enable hidpi stuff in the wrapper and I know how to write the code to use a scaling factor that can be multiplied by every coordinate, but this way is cumbersome and I have to change all coordinates of all X, Y, Width, Height after getting the code from Koda. Is there a fast way ? 
      So, what do you recommend me guys ?
      Thanks,
      Jowy
    • By LegitStack
      Been struggling with this one for a while. 
      when I do a _screencapture_capture call on a high resolution monitor (like my surface book) it gives me an image that has 2 problems:
      1. its in the wrong location on the screen
      and
      2. it gives me a picture that is larger than the area of the screen I selected, though it only has the content of what I selected. 
      ---------------------------
      I was able to easily fix problem #1 by manually adjusting the x y coordinates to compensate for the amount of DPI scale I have.
      for instance if I'm 200% zoomed in the code looks like this:
      Local $bmp = _ScreenCapture_Capture("", $iX1*2, $iY1*2, $iX2*2, $iY2*2, false)  it's problem #2 that is the big problem. I'd like to attach a screen shot of what I'm talking about (see capture.png)

      ---------------------------
      Now I basically understand why this is happening. ScreenCapture grabs each pixel of the screen. This screen, being a high resolution, when its zoomed in adds up several pixels to make one on the screen. 
      This is a problem for me because I'm taking images of the screen and later looking for those exact images on the screen. if everything is blown up by an indeterminate amount (in my case 2x) then those images can't be found later on. 
      Does anyone know what I can do? 
      I tried resizing the images back down to no avail. 
      _GDIPlus_ImageResize and _GDIPlus_ImageScale don't work because they don't compress the pixels correctly. quality is lost. and the exact image isn't preserved, so I can't search for it later. (see capture1.png)

       
      Anyway, I'm about to give up, been on this problem for too long! does anyone know what I can do? Seems to me that the ideal solution would be to eventually have autoit add an argument to _screencapture_capture that lets you specify a DPI scale amount or something.  that can be pulled from the registry at HKEY_CURRENT_USER\control panel\desktop\windowmetrics\appliedDPI.
      But in the meantime, does anyone have any suggestions for how I can make my program compatible with 4k resolution monitors? I either need to take the screen capture like normal, then scale it down appropriately without losing quality, or I need to capture the screen in the first place like the human sees it. But I don't know how to do that either. 
      I'll post my relevant code here: (in my project I call ScreenCapture_DPI_Aware)
      #include <Security.au3> Func _GetAppliedDPI()   Local $aArrayOfData = _Security__LookupAccountName(@UserName)   If IsArray($aArrayOfData) Then   ;msgbox(64, "SID String = ", $aArrayOfData[0] & @CRLF)   ;msgbox(64, "Domain name = ", $aArrayOfData[1] & @CRLF)   ;msgbox(64, "SID type = ", _Security__SidTypeStr($aArrayOfData[2]) & @CRLF)     ;Local $AppliedDPI = RegRead("HKEY_USERS\" & $aArrayOfData[0] & "\Control Panel\Desktop\WindowMetrics", "AppliedDPI") Local $AppliedDPI = RegRead("HKEY_CURRENT_USER\Control Panel\Desktop\WindowMetrics", "AppliedDPI")     return $AppliedDPI   EndIf EndFunc Func GetScale()   $applied = _GetAppliedDPI()   if $applied == "" then     return 1   else     return $applied / 96   EndIf EndFunc Func ScreenCapture_Capture_DPI_Aware($sBMP_Path, $iX1, $iY1, $iX2, $iY2, $bool)   $R = GetScale() ;Raito   Local $bmp = _ScreenCapture_Capture($sBMP_Path, $iX1*$R, $iY1*$R, $iX2*$R, $iY2*$R, $bool) ;Scaling didn't work: ;_ScaleImage($bmp, $sBMP_Path, abs($iX2 - $iX1), abs($iY2 - $iY1), $R)   ;return _ScreenCapture_Capture($sBMP_Path, $iX1*$R, $iY1*$R, $iX2*$R, $iY2*$R, $bool) EndFunc ;Func _ScaleImage($bmp, $outimage, $w, $h, $scale) ; _GDIPlus_Startup() ;Get the encoder of to save the resized image in the format you want. ; Local $Ext = StringUpper(StringMid($outimage, StringInStr($outimage, ".", 0, -1) + 1)) ; $CLSID = _GDIPlus_EncodersGetCLSID($Ext) ; code found here : https://www.autoitscript.com/autoit3/docs/libfunctions/_GDIPlus_ImageSaveToStream.htm ; Local $sImgCLSID = _GDIPlus_EncodersGetCLSID("png") ;create CLSID for a JPG image file type ; Local $tGUID = _WinAPI_GUIDFromString($sImgCLSID) ;convert CLSID GUID to binary form and returns $tagGUID structure ; Local $tParams = _GDIPlus_ParamInit(1) ;initialize an encoder parameter list and return $tagGDIPENCODERPARAMS structure ; Local $tData = DllStructCreate("int Quality") ;create struct to set JPG quality setting ; DllStructSetData($tData, "Quality", 100) ;quality 0-100 (0: lowest, 100: highest) ; Local $pData = DllStructGetPtr($tData) ;get pointer from quality struct ; _GDIPlus_ParamAdd($tParams, $GDIP_EPGQUALITY, 1, $GDIP_EPTLONG, $pData) ;add a value to an encoder parameter list ; Local $gbmp = _GDIPlus_BitmapCreateFromHBITMAP($bmp) ; _WinAPI_DeleteObject($bmp) ; Local $gsbmp = _GDIPlus_ImageResize($gbmp, $w * $scale, $h * $scale) ;Local $ext = _GDIPlus_EncodersGetCLSID("PNG") ; _GDIPlus_ImageSaveToFileEx($gsbmp, $outimage, $sImgCLSID) ; _GDIPlus_BitmapDispose($gbmp) ; _GDIPlus_BitmapDispose($gsbmp) ; _GDIPlus_Shutdown() ;EndFunc
      Thanks for any help you can give me!!!
×
×
  • Create New...