Jump to content

Need help with DllCall for GetProcessDpiAwareness


Mbee
 Share

Recommended Posts

@mLipok kindly provided a couple of DPI Awareness function interfaces here: Get Per-Monitor DPI Scaling Factor

To return that data, the user's process DPI awareness value has to be set to a particular value first. But as it is, that code simply sets it to the needed value, with no way of setting it back to the previous value. Thus, I tried to write an interface function that would return the existing value so that the user could optionally reset it. But it's not working the way I (perhaps stupidly) thought it would. Here's my code...

#include <Array.au3>
#include <ProcessConstants.au3>
#include <WinAPIHObj.au3>
#include <WinAPIProc.au3>
#include <WinAPIGdi.au3>
;
;   Author: mLipok
;   See: https://www.autoitscript.com/forum/topic/189341-get-per-monitor-dpi-scaling-factor/?do=findComment&comment=1468907
;

;   Possible return code values for this UDF

Global Const $S_OK              = 0
Global Const $E_ACCESSDENIED    = 0x80070005
Global Const $E_INVALIDARG      = 0x80070057


; enum _PROCESS_DPI_AWARENESS
Global Const $PROCESS_DPI_UNAWARE = 0
Global Const $PROCESS_SYSTEM_DPI_AWARE = 1
Global Const $PROCESS_PER_MONITOR_DPI_AWARE = 2

; enum _MONITOR_DPI_TYPE
Global Const $MDT_EFFECTIVE_DPI = 0
Global Const $MDT_ANGULAR_DPI = 1
Global Const $MDT_RAW_DPI = 2
Global Const $MDT_DEFAULT = $MDT_EFFECTIVE_DPI


Func _WinAPI_GetProcessDpiAwareness()                       ; By MBee
    Local $iAwareState = 47, $hProcess

    $hProcess = _WinAPI_GetCurrentProcess()
    If @error <> 0 Then
        Return SetError(@error, 0, -1)
    EndIf

    Local $aRet = DllCall("Shcore.dll", "long", "GetProcessDpiAwareness", "long", $hProcess, "uint*", $iAwareState)
    If @error = $S_OK Then
        Return SetError( 0, 0, $iRet )
    Else
        If @error = $E_INVALIDARG Then
            Return SetError(@error, 0, -2)
        ElseIf @error = $E_ACCESSDENIED Then
            Return SetError(@error, 0, -3)
        Else
            Return SetError(@error, 0, -4)
        EndIf
    EndIf

EndFunc   ;==>_WinAPI_GetProcessDpiAwareness

I thought that the Win API function would return the current state as a "ByRef" integer return value, $iAwareState. I thought the "*" in the parameter type description specified a ByRef return. But perhaps it does something else, like return a pointer to an integer? I just don't know. But upon return, @error is always 0 and the $iAwareState value remains unchanged at 47.

The Windows function also returns an array with three elements, which seems like it could be a full set of DPI values for different items, which has 3 elements, but I'm specifically asking for the Process DPI, so I expected only a single return value. At any rate, the return values in that array are 0, -1, 0. Which makes no sense if that actually is a DPI info array.

My guess is that I screwed up the DLLcall?

Thanks 

Link to comment
Share on other sites

For what it's worth, I tried enclosing the parameter names in quotes, which is what the old DLL Call Generator produced. Here is what it looks like with that change...

Func _WinAPI_GetProcessDpiAwareness()                       ; By MBee
    Local $iAwareState = 47, $hProcess

    $hProcess = _WinAPI_GetCurrentProcess()
    If @error <> 0 Then
        Return SetError(@error, 0, -1)
    EndIf

    Local $aRet = DllCall("Shcore.dll", "long", "GetProcessDpiAwareness", "HANDLE", "$hProcess", "int*", "$iAwareState")
    If @error = $S_OK Then
        Return SetError( 0, 0, $iAwareState )
    Else
        If @error = $E_INVALIDARG Then
            Return SetError(@error, 0, -2)
        ElseIf @error = $E_ACCESSDENIED Then
            Return SetError(@error, 0, -3)
        Else
            Return SetError(@error, 0, -4)
        EndIf
    EndIf

EndFunc   ;==>_WinAPI_GetProcessDpiAwareness

Unfortunately, it made no difference.

Link to comment
Share on other sites

OK, I'm pretty sure I figured it out. Here's my revised code for the function in question:

Func _WinAPI_GetProcessDpiAwareness()                       ; By MBee
    Local $iAwareState = 47, $hProcess

    $hProcess = _WinAPI_GetCurrentProcess()
    If @error <> 0 Then
        Return SetError(@error, 0, -1)
    EndIf

    Local $pInt = DllStructCreate( "INT" )

    Local $aRet = DllCall("Shcore.dll", "long", "GetProcessDpiAwareness", "HANDLE", $hProcess, "INT*", $pInt)
    If @error = $S_OK Then
        $iAwareState = DllStructGetData( $pInt, 1, 11 )
        Return SetError( 0, 0, $iAwareState )
    Else
        If @error = $E_INVALIDARG Then
            Return SetError(@error, 0, -2)
        ElseIf @error = $E_ACCESSDENIED Then
            Return SetError(@error, 0, -3)
        Else
            Return SetError(@error, 0, -4)
        EndIf
    EndIf

EndFunc   ;==>_WinAPI_GetProcessDpiAwareness

If that's not ideal, please let me know.  Thanks!  Now I can get back to documenting the new multi-monitor UDF(s) I wish to submit...

Link to comment
Share on other sites

Link to comment
Share on other sites

3 hours ago, Nine said:
Local $aRet = DllCall('Shcore.dll', 'int', 'GetProcessDpiAwareness', 'hwnd', 0, 'int*', 0)
ConsoleWrite ($aRet[2])

Need to check @error and $aRet[0] for potential errors

I'll do that, thanks! I had initially just passed zero, as you do, for the proc handle, but since at the time none of the returns were making sense, So I figured I'd try anything that looked at least somewhat plausible. By the way, though, I do check @error against zero, but I didn't see a description of the contents of the return array other than possibly a multi-level DPI return, which as I pointed out, is a 3-element array.

Thanks again!

Link to comment
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
 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...