Page 1 of 2 12 LastLast
Results 1 to 40 of 55

Thread: DPI Awareness per Window

  1. #1

    Thread Starter
    PowerPoster Elroy's Avatar
    Join Date
    Jun 2014
    Location
    Near Nashville TN
    Posts
    9,852

    DPI Awareness per Window

    Has anyone ever messed with specifying DPI awareness on a per Window (top level) basis? I know some will ask "why", but let's please set that aside for now.

    I've looked at a few of the API calls, but I haven't started testing just yet, just wondering if anyone else has messed with this.

    Also, I'm absolutely fine if we limit ourselves to Windows 10 (or above).
    Any software I post in these forums written by me is provided "AS IS" without warranty of any kind, expressed or implied, and permission is hereby granted, free of charge and without restriction, to any person obtaining a copy. To all, peace and happiness.

  2. #2
    PowerPoster
    Join Date
    Feb 2006
    Posts
    24,482

    Re: DPI Awareness per Window

    It is really only an issue for Per-Monitor DPI settings. There are two levels: PMv1 and PMv2 and they are handled differently.

    High DPI Desktop Application Development on Windows

    You might search on that phrase to find threads discussing it here.

  3. #3

    Thread Starter
    PowerPoster Elroy's Avatar
    Join Date
    Jun 2014
    Location
    Near Nashville TN
    Posts
    9,852

    Re: DPI Awareness per Window

    Quote Originally Posted by dilettante View Post
    It is really only an issue for Per-Monitor DPI settings. There are two levels: PMv1 and PMv2 and they are handled differently.

    High DPI Desktop Application Development on Windows

    You might search on that phrase to find threads discussing it here.
    I had actually just been reading that link before I started this thread. And yeah, it'd be nice if I could get per-monitor-and-per-window DPI aware going (obviously done with API calls to make it per-window).

    I'll start playing with it at some point, and post my progress.

    And yeah, I'll probably only explore PMv2, as I and all my users stay up-to-date with Windows 10.
    Any software I post in these forums written by me is provided "AS IS" without warranty of any kind, expressed or implied, and permission is hereby granted, free of charge and without restriction, to any person obtaining a copy. To all, peace and happiness.

  4. #4

    Thread Starter
    PowerPoster Elroy's Avatar
    Join Date
    Jun 2014
    Location
    Near Nashville TN
    Posts
    9,852

    Re: DPI Awareness per Window

    And also, apologies. I just realized that, once in the past, I started a similar thread. However, back then, I didn't come to a good resolution, so I'll soldier on with this one and see what I can figure out.
    Any software I post in these forums written by me is provided "AS IS" without warranty of any kind, expressed or implied, and permission is hereby granted, free of charge and without restriction, to any person obtaining a copy. To all, peace and happiness.

  5. #5
    PowerPoster
    Join Date
    Feb 2006
    Posts
    24,482

    Re: DPI Awareness per Window

    Good luck. It is very challenging to do this correctly, even File Explorer still has flaws.

  6. #6
    PowerPoster
    Join Date
    Feb 2017
    Posts
    4,995

    Re: DPI Awareness per Window

    Hello Elroy, I made one of my latest programs DPI aware per monitor V2.

    I've also been playing while considering to make a general purpose method for turning existing programs into DPI aware per monitor V2, but at the end abandoned the idea. The main problem is that it would require custom configurations for third party controls.

    If you have any question I would be glad to try to remember (or go to see) how to handle different things regarding DPI aware V2.

  7. #7
    PowerPoster
    Join Date
    Feb 2017
    Posts
    4,995

    Re: DPI Awareness per Window

    Well, the first thing is to manifest the IDE for DPI aware per monitor V2 to be able to test things there without having to compile.

  8. #8
    Fanatic Member
    Join Date
    Feb 2017
    Posts
    858

    Re: DPI Awareness per Window

    Per article:

    To enable sub-process DPI awareness, call SetThreadDpiAwarenessContext before and after any window creation calls
    Haven't played with any code yet, but wouldn't the simplest approach be to
    Set a Hook using:
    Code:
    If lMsg = HCBT_ACTIVATE Then
    
          Call SetThreadDpiAwarenessContext
       
          'Get the coordinates of the form 
    '      GetWindowRect Form1.hwnd, rectForm  
    
    hWnd = Form1.hwnd
    
    'Following MS C++ code
        int iDpi = GetDpiForWindow(hWnd); 
        int dpiScaledX = MulDiv(INITIALX_96DPI, iDpi, 96); 
        int dpiScaledY = MulDiv(INITIALY_96DPI, iDpi, 96); 
        int dpiScaledWidth = MulDiv(INITIALWIDTH_96DPI, iDpi, 96); 
        int dpiScaledHeight = MulDiv(INITIALHEIGHT_96DPI, iDpi, 96); 
        SetWindowPos(hWnd, hWnd, dpiScaledX, dpiScaledY, dpiScaledWidth, dpiScaledHeight, SWP_NOZORDER | SWP_NOACTIVATE);
     
    End If
    and then once the Original WindowRect is obtained, adjust it to using the DPI Rect and other DPI Functions.
    Last edited by vb6forever; Oct 25th, 2021 at 08:54 PM.

  9. #9
    PowerPoster
    Join Date
    Feb 2017
    Posts
    4,995

    Re: DPI Awareness per Window

    Quote Originally Posted by Elroy View Post
    Has anyone ever messed with specifying DPI awareness on a per Window (top level) basis? I know some will ask "why", but let's please set that aside for now.
    I'm not totally sure if when you say "per window" you mean:

    1) Windows (forms) that are on different monitors to adapt to the DPI of that monitor.

    2) To be able to set different DPI awareness for each window (form), like for example set Form1 as DPI aware per monitor, Form2 as DPI aware (system wide) and Form3 as DPI unaware.

    I answered in my previous posts assuming 1).
    And BTW, 2) is possible but it does not work well, it has important issues.

  10. #10
    Fanatic Member
    Join Date
    Feb 2017
    Posts
    858

    Re: DPI Awareness per Window

    Eduardo:
    I'm a newbie messing with DPI, but here's my first swipe approach (prior to pseudocode):

    Re: Per Window.
    Whether right or wrong the way I'm looking at approaching this is everything is a WindowRect.
    (ie. DPIScreen rect, Original Main Form (not DPI Window), and Any Original SubForms (not DPI Windows).
    So getting the DPIScreenRect allows one to calculate a ratio between the DPIScreen rect and the Orignal Forms or SubForms.
    That ratio (dpiScaleX and diScaleY) would then be passed to the DPI functions which would rescale any WIndow to DPI.
    So each DPIScreenRect (really the monitor) would have independent values that would be used to ReScale the Original App Main Window to DPI. Once those dpiScale factors are calculated, then using those ratios (dpiScaleX and dpiScaleY) can be used in a normal Resize routine to rescale controls.

    So at App StartuP one would obtain the Rect for the DPIScreenRect. A hook would then be set using lMsg = HCBT_ACTIVATE to obtain the Original AppRect. The dpiScaleX and dpiScaleY ratios could then be calculated and saved. Those dpiScaleX and dpiScaleY ratios would then be Applied to the Original AppRect to size it for DPI.
    For any subsequent Window the stored dpiScaleX and dpiScaleY would be use to NOT only adjust the SubWindow to the DPI settings, but execute a Resize Proc to adjust any Controls.
    Last edited by vb6forever; Oct 25th, 2021 at 10:45 PM.

  11. #11
    PowerPoster
    Join Date
    Feb 2017
    Posts
    4,995

    Re: DPI Awareness per Window

    Quote Originally Posted by vb6forever View Post
    Eduardo:
    I'm a newbie messing with DPI, but here's my first swipe approach (prior to pseudocode):

    Re: Per Window.
    Whether right or wrong the way I'm looking at approaching this is everything is a WindowRect.
    (ie. DPIScreen rect, Original Main Form (not DPI Window), and Any Original SubForms (not DPI Windows).
    So getting the DPIScreenRect allows one to calculate a ratio between the DPIScreen rect and the Orignal Forms or SubForms.
    That ratio (dpiScaleX and diScaleY) would then be passed to the DPI functions which would rescale any WIndow to DPI.
    So each DPIScreenRect (really the monitor) would have independent values that would be used to ReScale the Original App Main Window to DPI. Once those dpiScale factors are calculated, then using those ratios (dpiScaleX and dpiScaleY) can be used in a normal Resize routine to rescale controls.

    So at App StartuP one would obtain the Rect for the DPIScreenRect. A hook would then be set using lMsg = HCBT_ACTIVATE to obtain the Original AppRect. The dpiScaleX and dpiScaleY ratios could then be calculated and saved. Those dpiScaleX and dpiScaleY ratios would then be Applied to the Original AppRect to size it for DPI.
    For any subsequent Window the stored dpiScaleX and dpiScaleY would be use to NOT only adjust the SubWindow to the DPI settings, but execute a Resize Proc to adjust any Controls.
    Some points:

    - dpiScaleX and dpiScaleY are the same on current Windows.

    - In most cases, DPI aware (system wide, not per monitor) is enough because for the secondary monitors the automatic scaling that Windows performs if good enough. And it is much easier to make the programs just DPI aware and not DPI aware per monitor (when I say per monitor I mean per monitor V2).

    - For DPI aware per monitor from the top of my mind I remember:

    a) Resize the form
    b) Reposition and resize the controls
    c) Scale the fonts
    d) Scale the images (icons, whatever)
    e) Redo everything above responding the certain window messages that inform about:

    I) a DPI change
    II) the window changed monitor (most probably because it was dragged by the user).

    In the program that I made it, it had only a few forms, but in a program with many forms, doing that without an automatic mechanism can be very time consuming.

  12. #12
    Fanatic Member
    Join Date
    Feb 2017
    Posts
    858

    Re: DPI Awareness per Window

    Eduardo, thanks for your feedback.

    - In most cases, DPI aware (system wide, not per monitor) is enough because for the secondary monitors the automatic scaling that Windows performs if good enough. And it is much easier to make the programs just DPI aware and not DPI aware per monitor (when I say per monitor I mean per monitor V2).
    I would think going system wide, with multi-monitors would create an issue.
    1) EACH monitor might have a different DPI
    (The system would know those DPI setting so should be OK)

    BUT
    2) DPI, as I see it, would have the same PITFALLS of trying to resize a form in the past.
    That is some controls do well, others Not, and getting the Font Size to look right based on new Scale always seemed to be an issue. Letting the SYSTEM handle that for secondary monitors might not properly reflect -- visually -- what's on the screen since the coder has given up control and what appears OK to one person, may not look good to another.
    Last edited by vb6forever; Oct 26th, 2021 at 06:40 AM.

  13. #13
    PowerPoster
    Join Date
    Feb 2017
    Posts
    4,995

    Re: DPI Awareness per Window

    Quote Originally Posted by vb6forever View Post
    getting the Font Size to look right based on new Scale always seemed to be an issue.
    You have to leave some space between controls to have some tolerance.
    For system wide dpi aware it is the same.

    Quote Originally Posted by vb6forever View Post
    Letting the SYSTEM handle that for secondary monitors might not properly reflect -- visually -- what's on the screen since the coder has given up control and what appears OK to one person, may not look good to another.
    The virtualization that Windows does automatically works very well, everything is scaled right, but there is only a little blurring. That's the price: little blurring, not very noticeable on secondary monitors that have other DPI setting than the main monitor.

  14. #14
    PowerPoster
    Join Date
    Feb 2006
    Posts
    24,482

    Re: DPI Awareness per Window

    Quote Originally Posted by Eduardo- View Post
    - dpiScaleX and dpiScaleY are the same on current Windows.
    Nope. This is strictly an accident of common display adapters and their most common settings. Non-square pixels are rare on displays today though they remain fairly common on printers.

    This can pop up anywhere though, and there is no reason to make the assumption it won't. Just use separate scaling metrics for X and Y and nip possible problems in the bud. Windows tracks these separately for good reasons and your programs should as well.

  15. #15
    PowerPoster
    Join Date
    Feb 2017
    Posts
    4,995

    Re: DPI Awareness per Window

    Quote Originally Posted by dilettante View Post
    Nope. This is strictly an accident of common display adapters and their most common settings. Non-square pixels are rare on displays today though they remain fairly common on printers.

    This can pop up anywhere though, and there is no reason to make the assumption it won't. Just use separate scaling metrics for X and Y and nip possible problems in the bud. Windows tracks these separately for good reasons and your programs should as well.
    - We are talking about monitors, not printers.

    - I have always used separate scales so far but I saw that even Windows do not use separate scales for X and Y in latest APIs anymore.

  16. #16

    Thread Starter
    PowerPoster Elroy's Avatar
    Join Date
    Jun 2014
    Location
    Near Nashville TN
    Posts
    9,852

    Re: DPI Awareness per Window

    Quote Originally Posted by Eduardo- View Post
    Well, the first thing is to manifest the IDE for DPI aware per monitor V2 to be able to test things there without having to compile.
    I would tend to agree, but I'm a bit confused on that issue.

    There's no .manifest for my IDE, and I certainly haven't messed with the resources of my VB6.EXE file. However, I do seem to have IDE per monitor awareness.

    Here's some Form1 code I ran to check this:

    Code:
    
    Option Explicit
    '
    Private Enum DPI_AWARENESS
      DPI_AWARENESS_INVALID = -1&           ' Invalid DPI awareness. This is an invalid DPI awareness value.
      DPI_AWARENESS_UNAWARE = 0&            ' DPI unaware. This process does not scale for DPI changes and is always assumed to have a scale factor of 100% (96 DPI). It will be automatically scaled by the system on any other DPI setting.
      DPI_AWARENESS_SYSTEM_AWARE = 1&       ' System DPI aware. This process does not scale for DPI changes. It will query for the DPI once and use that value for the lifetime of the process. If the DPI changes, the process will not adjust to the new DPI value. It will be automatically scaled up or down by the system when the DPI changes from the system value.
      DPI_AWARENESS_PER_MONITOR_AWARE = 2&  ' Per monitor DPI aware. This process checks for the DPI when it is created and adjusts the scale factor whenever the DPI changes. These processes are not automatically scaled by the system.
    End Enum
    '
    Private Declare Function GetThreadDpiAwarenessContext Lib "user32" () As Long ' The current DPI_AWARENESS_CONTEXT handle for the thread.
    Private Declare Function GetAwarenessFromDpiAwarenessContext Lib "user32" (ByVal hDpiContext As Long) As Long ' The DPI_AWARENESS. If the provided value is 0 or invalid, return=DPI_AWARENESS_INVALID.
    '
    
    Private Function DpiAwareness(iDpiAwareness As DPI_AWARENESS) As String
        Select Case iDpiAwareness
        Case DPI_AWARENESS_INVALID:             DpiAwareness = "Invalid"
        Case DPI_AWARENESS_UNAWARE:             DpiAwareness = "Unaware"
        Case DPI_AWARENESS_SYSTEM_AWARE:        DpiAwareness = "Per System"
        Case DPI_AWARENESS_PER_MONITOR_AWARE:   DpiAwareness = "Per Monitor"
        Case Else:                              DpiAwareness = "Not in enum"
        End Select
    End Function
    
    
    Private Sub Form_Load()
        Dim hDpiContext As Long
        hDpiContext = GetThreadDpiAwarenessContext
    
        Dim iAwareness As Long
        iAwareness = GetAwarenessFromDpiAwarenessContext(hDpiContext)
    
        Debug.Print hDpiContext, DpiAwareness(iAwareness)
    End Sub
    
    And here's what I got in the Immediate window:

    Code:
     18          Per Monitor
    So, I started snooping into my VB6.EXE settings (thinking maybe I'd changed them at some point), and here's what I've got:

    Name:  DpiAwareness.jpg
Views: 904
Size:  38.6 KB

    (Also as a PNG in a ZIP attachment so you can see it better, if you need to.)
    Attached Files Attached Files
    Any software I post in these forums written by me is provided "AS IS" without warranty of any kind, expressed or implied, and permission is hereby granted, free of charge and without restriction, to any person obtaining a copy. To all, peace and happiness.

  17. #17
    PowerPoster
    Join Date
    Feb 2006
    Posts
    24,482

    Re: DPI Awareness per Window

    Quote Originally Posted by Eduardo- View Post
    - We are talking about monitors, not printers.

    - I have always used separate scales so far but I saw that even Windows do not use separate scales for X and Y in latest APIs anymore.
    True, but that's a scaling factor only meant to be used in calling GetSystemMetricsForDpi() and not ever for direct use. The metrics themselves have separate X and Y values.

  18. #18
    Fanatic Member
    Join Date
    Feb 2017
    Posts
    858

    Re: DPI Awareness per Window

    Here's an interesting discussion of dealing with Font Scaling:

    https://bits.theorem.co/css-pro-tips...e-which-units/

  19. #19
    PowerPoster
    Join Date
    Feb 2006
    Posts
    24,482

    Re: DPI Awareness per Window

    Quote Originally Posted by vb6forever View Post
    Here's an interesting discussion of dealing with Font Scaling:

    https://bits.theorem.co/css-pro-tips...e-which-units/
    Doesn't look too interesting. CSS and browser rendering are entirely different topics.

  20. #20
    PowerPoster
    Join Date
    Feb 2006
    Posts
    24,482

    Re: DPI Awareness per Window

    We're probably off in the weeds.

    I think the original question was about setting different DPI Scaling "awareness" (actually appcompat) on different Forms.

  21. #21
    Fanatic Member
    Join Date
    Feb 2017
    Posts
    858

    Re: DPI Awareness per Window

    dilettante: Whether a browser window or desk app, still has to appear on the screen.
    What I got from the article is to look at each text sting as being contained in its own RECT (viewport) and size to that viewport.
    Using the concept one uses to size a circle, I believe would also work for Text, but basing that sizing on the text RECT (viewport) scale, Not the screen scale. Just some thoughts!
    Last edited by vb6forever; Oct 26th, 2021 at 09:22 AM.

  22. #22
    PowerPoster
    Join Date
    Feb 2006
    Posts
    24,482

    Re: DPI Awareness per Window

    No, the article is suggesting avoiding pixel-based metrics. We already have that rule in VB6, where font height is in points.

  23. #23

    Thread Starter
    PowerPoster Elroy's Avatar
    Join Date
    Jun 2014
    Location
    Near Nashville TN
    Posts
    9,852

    Re: DPI Awareness per Window

    Yeah, y'all are off in the weeds.

    Let me see if I can pull it back to where I'd like to go.

    I've declared this enumeration, based on my attempt to understand things:

    Code:
    
    Public Enum DPI_AWARENESS_CONTEXT
        Context_Undefined = 0&
        Context_Unaware = -1&                   ' DPI unaware. This window does not scale for DPI changes and is always assumed to have a scale factor of 100% (96 DPI). It will be automatically scaled by the system on any other DPI setting.
        Context_SystemAware = -2&               ' System DPI aware. This window does not scale for DPI changes. It will query for the DPI once and use that value for the lifetime of the process. If the DPI changes, the process will not adjust to the new DPI value. It will be automatically scaled up or down by the system when the DPI changes from the system value.
        Context_PerMonitorAware = -3&           ' Per monitor DPI aware. This window checks for the DPI when it is created and adjusts the scale factor whenever the DPI changes. These processes are not automatically scaled by the system.
        Context_PerMonitorAwareV2 = -4&         ' Also known as Per Monitor v2. An advancement over the original per-monitor DPI awareness mode, which enables applications to access new DPI-related scaling behaviors on a per top-level window basis.
        Context_UnawareGdiScaled = -5&          ' DPI unaware with improved quality of GDI-based content. This mode behaves similarly to DPI_AWARENESS_CONTEXT_UNAWARE, but also enables the system to automatically improve the rendering quality of text and other GDI-based primitives when the window is displayed on a high-DPI monitor.
    End Enum
    
    
    However, when I call GetThreadDpiAwarenessContext, it returns a value of 18. Any ideas on why that is, and what the meaning of that 18 is?
    Any software I post in these forums written by me is provided "AS IS" without warranty of any kind, expressed or implied, and permission is hereby granted, free of charge and without restriction, to any person obtaining a copy. To all, peace and happiness.

  24. #24
    PowerPoster
    Join Date
    Feb 2006
    Posts
    24,482

    Re: DPI Awareness per Window

    You don't want to look at that handle, instead you'll want to look up what it means:

    Code:
    Option Explicit
    
    Private Const WIN32_FALSE As Long = 0
    
    Private Enum DPI_AWARENESS
        DPI_AWARENESS_INVALID = -1
        DPI_AWARENESS_UNAWARE = 0
        DPI_AWARENESS_SYSTEM_AWARE = 1
        DPI_AWARENESS_PER_MONITOR_AWARE = 2
        'DPI_AWARENESS_UNAWARE_GDISCALED is not defined.
    End Enum
    
    Private Enum DPI_AWARENESS_CONTEXTS
        DPI_AWARENESS_CONTEXT_UNAWARE = -1
        DPI_AWARENESS_CONTEXT_SYSTEM_AWARE = -2
        DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE = -3
        DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2 = -4
        DPI_AWARENESS_CONTEXT_UNAWARE_GDISCALED = -5
    End Enum
    
    Private Declare Function GetAwarenessFromDpiAwarenessContext Lib "user32" ( _
        ByVal hValue As Long) As DPI_AWARENESS
        
    Private Declare Function GetThreadDpiAwarenessContext Lib "user32" () As Long
    
    Private Declare Function IsValidDpiAwarenessContext Lib "user32" ( _
        ByVal hValue As Long) As Long
    
    Private Declare Function SetThreadDpiAwarenessContext Lib "user32" ( _
        ByVal dpiContext As DPI_AWARENESS_CONTEXTS) As Long
    
    Private Sub Form_Load()
        Dim hPrevValue As Long
    
        Debug.Print GetAwarenessFromDpiAwarenessContext(GetThreadDpiAwarenessContext())
        Debug.Print , IsValidDpiAwarenessContext(DPI_AWARENESS_CONTEXT_UNAWARE_GDISCALED) <> WIN32_FALSE
        hPrevValue = SetThreadDpiAwarenessContext(DPI_AWARENESS_CONTEXT_UNAWARE_GDISCALED)
        Debug.Print , , hPrevValue
        Debug.Print , , , GetAwarenessFromDpiAwarenessContext(hPrevValue)
        Debug.Print , , , , GetAwarenessFromDpiAwarenessContext(GetThreadDpiAwarenessContext())
    End Sub
    Last edited by dilettante; Oct 26th, 2021 at 11:24 AM. Reason: corrected an error, expanded the demo

  25. #25
    PowerPoster
    Join Date
    Feb 2017
    Posts
    4,995

    Re: DPI Awareness per Window

    Quote Originally Posted by dilettante View Post
    True, but that's a scaling factor only meant to be used in calling GetSystemMetricsForDpi() and not ever for direct use. The metrics themselves have separate X and Y values.
    Where did you read that GetDpiForWindow has to be used only with GetSystemMetricsForDpi?

    The explanation in the official documentation says:

    Returns the dots per inch (dpi) value for the associated window.
    DPI are DPI.
    It is like saying: this is a ruler, but is is only meant to measure iron screws, not nails or other things.

    Look the explanation of GetDpiForMonitor, that is an older API:

    The values of *dpiX and *dpiY are identical. You only need to record one of the values to determine the DPI and respond appropriately.

  26. #26
    PowerPoster
    Join Date
    Feb 2006
    Posts
    24,482

    Re: DPI Awareness per Window

    When that cigar blows up in your face don't say you weren't warned.

  27. #27
    PowerPoster
    Join Date
    Feb 2017
    Posts
    4,995

    Re: DPI Awareness per Window

    Quote Originally Posted by Elroy View Post
    I would tend to agree, but I'm a bit confused on that issue.

    There's no .manifest for my IDE, and I certainly haven't messed with the resources of my VB6.EXE file. However, I do seem to have IDE per monitor awareness.

    Here's some Form1 code I ran to check this:

    Code:
    
    Option Explicit
    '
    Private Enum DPI_AWARENESS
      DPI_AWARENESS_INVALID = -1&           ' Invalid DPI awareness. This is an invalid DPI awareness value.
      DPI_AWARENESS_UNAWARE = 0&            ' DPI unaware. This process does not scale for DPI changes and is always assumed to have a scale factor of 100% (96 DPI). It will be automatically scaled by the system on any other DPI setting.
      DPI_AWARENESS_SYSTEM_AWARE = 1&       ' System DPI aware. This process does not scale for DPI changes. It will query for the DPI once and use that value for the lifetime of the process. If the DPI changes, the process will not adjust to the new DPI value. It will be automatically scaled up or down by the system when the DPI changes from the system value.
      DPI_AWARENESS_PER_MONITOR_AWARE = 2&  ' Per monitor DPI aware. This process checks for the DPI when it is created and adjusts the scale factor whenever the DPI changes. These processes are not automatically scaled by the system.
    End Enum
    '
    Private Declare Function GetThreadDpiAwarenessContext Lib "user32" () As Long ' The current DPI_AWARENESS_CONTEXT handle for the thread.
    Private Declare Function GetAwarenessFromDpiAwarenessContext Lib "user32" (ByVal hDpiContext As Long) As Long ' The DPI_AWARENESS. If the provided value is 0 or invalid, return=DPI_AWARENESS_INVALID.
    '
    
    Private Function DpiAwareness(iDpiAwareness As DPI_AWARENESS) As String
        Select Case iDpiAwareness
        Case DPI_AWARENESS_INVALID:             DpiAwareness = "Invalid"
        Case DPI_AWARENESS_UNAWARE:             DpiAwareness = "Unaware"
        Case DPI_AWARENESS_SYSTEM_AWARE:        DpiAwareness = "Per System"
        Case DPI_AWARENESS_PER_MONITOR_AWARE:   DpiAwareness = "Per Monitor"
        Case Else:                              DpiAwareness = "Not in enum"
        End Select
    End Function
    
    
    Private Sub Form_Load()
        Dim hDpiContext As Long
        hDpiContext = GetThreadDpiAwarenessContext
    
        Dim iAwareness As Long
        iAwareness = GetAwarenessFromDpiAwarenessContext(hDpiContext)
    
        Debug.Print hDpiContext, DpiAwareness(iAwareness)
    End Sub
    
    And here's what I got in the Immediate window:

    Code:
     18          Per Monitor
    So, I started snooping into my VB6.EXE settings (thinking maybe I'd changed them at some point), and here's what I've got:

    Name:  DpiAwareness.jpg
Views: 904
Size:  38.6 KB

    (Also as a PNG in a ZIP attachment so you can see it better, if you need to.)
    I don't know why you are getting per monitor, I tested with the original VB6.exe (without manifest) and I get unaware. About the Windows properties, I get for that exe the same as you do.

  28. #28

    Thread Starter
    PowerPoster Elroy's Avatar
    Join Date
    Jun 2014
    Location
    Near Nashville TN
    Posts
    9,852

    Re: DPI Awareness per Window

    Ok, so, with one of these constants ...

    Code:
    
    Public Enum DPI_AWARENESS_CONTEXT
        Context_Undefined = 0&
        Context_Unaware = -1&                   ' DPI unaware. This window does not scale for DPI changes and is always assumed to have a scale factor of 100% (96 DPI). It will be automatically scaled by the system on any other DPI setting.
        Context_SystemAware = -2&               ' System DPI aware. This window does not scale for DPI changes. It will query for the DPI once and use that value for the lifetime of the process. If the DPI changes, the process will not adjust to the new DPI value. It will be automatically scaled up or down by the system when the DPI changes from the system value.
        Context_PerMonitorAware = -3&           ' Per monitor DPI aware. This window checks for the DPI when it is created and adjusts the scale factor whenever the DPI changes. These processes are not automatically scaled by the system.
        Context_PerMonitorAwareV2 = -4&         ' Also known as Per Monitor v2. An advancement over the original per-monitor DPI awareness mode, which enables applications to access new DPI-related scaling behaviors on a per top-level window basis.
        Context_UnawareGdiScaled = -5&          ' DPI unaware with improved quality of GDI-based content. This mode behaves similarly to DPI_AWARENESS_CONTEXT_UNAWARE, but also enables the system to automatically improve the rendering quality of text and other GDI-based primitives when the window is displayed on a high-DPI monitor.
    End Enum
    
    ... I can make a call to SetThreadDpiAwarenessContext or SetProcessDpiAwarenessContext?

    I'm confused because the MSDN says "handles" are the input to those calls. Or, do I have to somehow convert those constants to a "handle"? If so, how would I go about doing that?
    Any software I post in these forums written by me is provided "AS IS" without warranty of any kind, expressed or implied, and permission is hereby granted, free of charge and without restriction, to any person obtaining a copy. To all, peace and happiness.

  29. #29

    Thread Starter
    PowerPoster Elroy's Avatar
    Join Date
    Jun 2014
    Location
    Near Nashville TN
    Posts
    9,852

    Re: DPI Awareness per Window

    Quote Originally Posted by Eduardo- View Post
    I don't know why you are getting per monitor, I tested with the original VB6.exe (without manifest) and I get unaware. About the Windows properties, I get for that exe the same as you do.
    Weird. I'll keep looking into it.
    Any software I post in these forums written by me is provided "AS IS" without warranty of any kind, expressed or implied, and permission is hereby granted, free of charge and without restriction, to any person obtaining a copy. To all, peace and happiness.

  30. #30
    PowerPoster
    Join Date
    Feb 2017
    Posts
    4,995

    Re: DPI Awareness per Window

    Quote Originally Posted by dilettante View Post
    When that cigar blows up in your face don't say you weren't warned.
    I presented the evidence that points that difference between DPI_X and DPI_Y is left behind by MS (regarding to monitors). If you think I am wrong, you are more than welcome to make corrections by presenting evidence.

    I think if you were an attorney dilettante, you would lose all the cases, you only insult to the other party.

  31. #31

    Thread Starter
    PowerPoster Elroy's Avatar
    Join Date
    Jun 2014
    Location
    Near Nashville TN
    Posts
    9,852

    Re: DPI Awareness per Window

    Ok, I think I figured out the issue with returning "DPI_AWARENESS_PER_MONITOR_AWARE" from the IDE.

    I've got the "HighDpiAware" shim set in my SDB file that I use with the IDE.
    Any software I post in these forums written by me is provided "AS IS" without warranty of any kind, expressed or implied, and permission is hereby granted, free of charge and without restriction, to any person obtaining a copy. To all, peace and happiness.

  32. #32

    Thread Starter
    PowerPoster Elroy's Avatar
    Join Date
    Jun 2014
    Location
    Near Nashville TN
    Posts
    9,852

    Re: DPI Awareness per Window

    Ok, just shoving the DPI_AWARENESS_CONTEXT enum constants (0 thru -5) into SetThreadDpiAwarenessContext seems to work.

    As Dil says, I guess we just pretty much ignore the return values of GetThreadDpiAwarenessContext or GetProcessDpiAwarenessContext, or maybe stick them into GetAwarenessFromDpiAwarenessContext, IsValidDpiAwarenessContext, or AreDpiAwarenessContextsEqual.

    And here's some interesting stuff. This comes back TRUE:

    Code:
    
    Debug.Print AreDpiAwarenessContextsEqual(-2147483630, Context_PerMonitorAware)
    
    
    And this is where -2147483630 was the return of GetThreadDpiAwarenessContext and Context_PerMonitorAware=-3& per the enum.

    The following also returns TRUE:

    Code:
    
    Debug.Print AreDpiAwarenessContextsEqual(34, Context_PerMonitorAwareV2)
    
    
    So, I guess we can put together a function something like the following:

    Code:
    
    Public Function CoreAwarenessContext(ByVal hDpiContext As Long) As DPI_AWARENESS_CONTEXT
        Select Case True
        Case AreDpiAwarenessContextsEqual(hDpiContext, Context_UnawareGdiScaled):   CoreAwarenessContext = Context_UnawareGdiScaled
        Case AreDpiAwarenessContextsEqual(hDpiContext, Context_PerMonitorAwareV2):  CoreAwarenessContext = Context_PerMonitorAwareV2
        Case AreDpiAwarenessContextsEqual(hDpiContext, Context_PerMonitorAware):    CoreAwarenessContext = Context_PerMonitorAware
        Case AreDpiAwarenessContextsEqual(hDpiContext, Context_SystemAware):        CoreAwarenessContext = Context_SystemAware
        Case AreDpiAwarenessContextsEqual(hDpiContext, Context_Unaware):            CoreAwarenessContext = Context_Unaware
        Case Else:                                                                  CoreAwarenessContext = Context_Undefined
        End Select
    End Function
    
    Any software I post in these forums written by me is provided "AS IS" without warranty of any kind, expressed or implied, and permission is hereby granted, free of charge and without restriction, to any person obtaining a copy. To all, peace and happiness.

  33. #33
    PowerPoster
    Join Date
    Feb 2006
    Posts
    24,482

    Re: DPI Awareness per Window

    Quote Originally Posted by Elroy View Post
    I've got the "HighDpiAware" shim set in my SDB file that I use with the IDE.
    Yes. That will do it.

  34. #34

    Thread Starter
    PowerPoster Elroy's Avatar
    Join Date
    Jun 2014
    Location
    Near Nashville TN
    Posts
    9,852

    Re: DPI Awareness per Window

    Also, I'm becoming convinced that we don't need to manifest (nor shim) the IDE to use this stuff.

    Eduardo, if you have a moment, could you run the following code (in a Form1) and tell me what you get?

    Code:
    
    Option Explicit
    '
    Private Enum DPI_AWARENESS_CONTEXT
        Context_Undefined = 0&
        Context_Unaware = -1&
        Context_SystemAware = -2&
        Context_PerMonitorAware = -3&
        Context_PerMonitorAwareV2 = -4&
        Context_UnawareGdiScaled = -5&
    End Enum
    Private Declare Function AreDpiAwarenessContextsEqual Lib "user32" (ByVal hDpiContextA As Long, ByVal hDpiContextB As Long) As Long ' Returns TRUE if the values are equal, otherwise FALSE.
    Private Declare Function GetThreadDpiAwarenessContext Lib "user32" () As Long ' The current DPI_AWARENESS_CONTEXT handle for the thread.
    Private Declare Function SetThreadDpiAwarenessContext Lib "user32" (ByVal hDpiContext As Long) As Long ' Returns the OLD awareness context handle.
    
    Private Sub Form_Load()
        Dim hOldDpiContext As Long
        Dim hNewDpiContext As Long
    
        hOldDpiContext = SetThreadDpiAwarenessContext(Context_PerMonitorAwareV2)
        hNewDpiContext = GetThreadDpiAwarenessContext()
        Debug.Print CoreAwarenessContextDesc(hOldDpiContext) & vbNewLine & CoreAwarenessContextDesc(hNewDpiContext)
        MsgBox CoreAwarenessContextDesc(hOldDpiContext) & vbNewLine & CoreAwarenessContextDesc(hNewDpiContext)
        SetThreadDpiAwarenessContext hOldDpiContext     ' Put it back, per MSDN.
    
        Unload Me
    
    End Sub
    
    
    Private Function CoreAwarenessContextDesc(ByVal hDpiContext As Long) As String
        Select Case True
        Case AreDpiAwarenessContextsEqual(hDpiContext, Context_UnawareGdiScaled):   CoreAwarenessContextDesc = "Unaware Gdi Scaled"
        Case AreDpiAwarenessContextsEqual(hDpiContext, Context_PerMonitorAwareV2):  CoreAwarenessContextDesc = "Per Monitor Aware V2"
        Case AreDpiAwarenessContextsEqual(hDpiContext, Context_PerMonitorAware):    CoreAwarenessContextDesc = "Per Monitor Aware V1"
        Case AreDpiAwarenessContextsEqual(hDpiContext, Context_SystemAware):        CoreAwarenessContextDesc = "System Aware"
        Case AreDpiAwarenessContextsEqual(hDpiContext, Context_Unaware):            CoreAwarenessContextDesc = "Unaware"
        Case Else:                                                                  CoreAwarenessContextDesc = "Undefined"
        End Select
    End Function
    
    I get "Per Monitor Aware V1" for the old/first one, and "Per Monitor Aware V2" for the new/second one.

    Thanks in advance.

    EDIT: I changed it a bit so you'd get both the old context and the new context. Now, anyone who has a mind to can do this test and report their results.
    Last edited by Elroy; Oct 26th, 2021 at 11:42 AM.
    Any software I post in these forums written by me is provided "AS IS" without warranty of any kind, expressed or implied, and permission is hereby granted, free of charge and without restriction, to any person obtaining a copy. To all, peace and happiness.

  35. #35
    Fanatic Member
    Join Date
    Feb 2017
    Posts
    858

    Re: DPI Awareness per Window

    Elroy:

    Running Win10 (latest) with VB5,
    Put code into VB5 Single App in Form_Load.
    My Old Monitor Reports:

    Per Monitor Aware V1
    Per Monitor Aware V2
    Last edited by vb6forever; Oct 26th, 2021 at 01:22 PM.

  36. #36
    PowerPoster
    Join Date
    Feb 2017
    Posts
    4,995

    Re: DPI Awareness per Window

    Quote Originally Posted by Elroy View Post
    Also, I'm becoming convinced that we don't need to manifest (nor shim) the IDE to use this stuff.

    Eduardo, if you have a moment, could you run the following code (in a Form1) and tell me what you get?
    I reports as it changes the thread awareness but I don't see any change regarding blurriness, even of forms showed after the awareness changes (I commented the last line that restores the old awareness).

    I think there were issues when changing the awareness like that by code.

    Even if that worked well, you would have to change the awareness before the form load (in a Sub Main or Form Initialize).

    But I don't know what is really happening, because if I put this code in a command button:

    Code:
        Dim hOldDpiContext As Long
        Dim hNewDpiContext As Long
    
        hOldDpiContext = SetThreadDpiAwarenessContext(Context_PerMonitorAwareV2)
        hNewDpiContext = GetThreadDpiAwarenessContext()
        Debug.Print CoreAwarenessContextDesc(hOldDpiContext) & vbNewLine & CoreAwarenessContextDesc(hNewDpiContext)
        MsgBox CoreAwarenessContextDesc(hOldDpiContext) & vbNewLine & CoreAwarenessContextDesc(hNewDpiContext)
    
        hOldDpiContext = SetThreadDpiAwarenessContext(Context_PerMonitorAwareV2)
        hNewDpiContext = GetThreadDpiAwarenessContext()
        Debug.Print CoreAwarenessContextDesc(hOldDpiContext) & vbNewLine & CoreAwarenessContextDesc(hNewDpiContext)
        MsgBox CoreAwarenessContextDesc(hOldDpiContext) & vbNewLine & CoreAwarenessContextDesc(hNewDpiContext)
    In the second call there in the procedure I get that the awareness remains changed, but if I click the button again, the fist call report "unaware" again. Weird.

    As I said, there were issues changing the awareness like that, but I don't remember what they were because I discarded that option. Perhaps someone else does.

  37. #37

    Thread Starter
    PowerPoster Elroy's Avatar
    Join Date
    Jun 2014
    Location
    Near Nashville TN
    Posts
    9,852

    Re: DPI Awareness per Window

    @vb6forever: Thanks, yeah, you're getting the same thing as me on my primary computer.

    I just tried it on another computer that doesn't have any shims or anything else set on the VB6 IDE. Over there, I got:

    Code:
    Unaware
    Per Monitor Aware V2
    So, that pretty much confirms to me that we can change this awareness context from anything to anything we like. And, it doesn't matter how the program is manifested (or shimmed or whatever).

    @Edwardo: I'm pretty sure what I was doing (in post #34) was changing the awareness context for the thread, and all windows created from that point forward (unless it's changed again). So, the context isn't really associated with any window at that point.

    From my current testing, I'm clearly getting different awareness contexts for different windows, all in the same program (both within the IDE and compiled). But I'm still getting some confusions. I'll post those in a moment.
    Any software I post in these forums written by me is provided "AS IS" without warranty of any kind, expressed or implied, and permission is hereby granted, free of charge and without restriction, to any person obtaining a copy. To all, peace and happiness.

  38. #38
    PowerPoster
    Join Date
    Feb 2017
    Posts
    4,995

    Re: DPI Awareness per Window

    Quote Originally Posted by Elroy View Post
    @Edwardo: I'm pretty sure what I was doing (in post #34) was changing the awareness context for the thread, and all windows created from that point forward (unless it's changed again). So, the context isn't really associated with any window at that point.

    From my current testing, I'm clearly getting different awareness contexts for different windows, all in the same program (both within the IDE and compiled). But I'm still getting some confusions. I'll post those in a moment.
    Did you test what I said in my last post (that the awareness seems not to remain changed for long)?

    Here is the code:

    Code:
    Option Explicit
    '
    Private Enum DPI_AWARENESS_CONTEXT
        Context_Undefined = 0&
        Context_Unaware = -1&
        Context_SystemAware = -2&
        Context_PerMonitorAware = -3&
        Context_PerMonitorAwareV2 = -4&
        Context_UnawareGdiScaled = -5&
    End Enum
    Private Declare Function AreDpiAwarenessContextsEqual Lib "user32" (ByVal hDpiContextA As Long, ByVal hDpiContextB As Long) As Long ' Returns TRUE if the values are equal, otherwise FALSE.
    Private Declare Function GetThreadDpiAwarenessContext Lib "user32" () As Long ' The current DPI_AWARENESS_CONTEXT handle for the thread.
    Private Declare Function SetThreadDpiAwarenessContext Lib "user32" (ByVal hDpiContext As Long) As Long ' Returns the OLD awareness context handle.
    
    Private Function CoreAwarenessContextDesc(ByVal hDpiContext As Long) As String
        Select Case True
        Case AreDpiAwarenessContextsEqual(hDpiContext, Context_UnawareGdiScaled):   CoreAwarenessContextDesc = "Unaware Gdi Scaled"
        Case AreDpiAwarenessContextsEqual(hDpiContext, Context_PerMonitorAwareV2):  CoreAwarenessContextDesc = "Per Monitor Aware V2"
        Case AreDpiAwarenessContextsEqual(hDpiContext, Context_PerMonitorAware):    CoreAwarenessContextDesc = "Per Monitor Aware V1"
        Case AreDpiAwarenessContextsEqual(hDpiContext, Context_SystemAware):        CoreAwarenessContextDesc = "System Aware"
        Case AreDpiAwarenessContextsEqual(hDpiContext, Context_Unaware):            CoreAwarenessContextDesc = "Unaware"
        Case Else:                                                                  CoreAwarenessContextDesc = "Undefined"
        End Select
    End Function
    
    Private Sub Command1_Click()
        Dim hOldDpiContext As Long
    
        hOldDpiContext = SetThreadDpiAwarenessContext(Context_PerMonitorAwareV2)
        Command2_Click
    End Sub
    
    Private Sub Command2_Click()
        Dim hNewDpiContext As Long
        
        hNewDpiContext = GetThreadDpiAwarenessContext()
        MsgBox CoreAwarenessContextDesc(hNewDpiContext)
    End Sub

  39. #39

    Thread Starter
    PowerPoster Elroy's Avatar
    Join Date
    Jun 2014
    Location
    Near Nashville TN
    Posts
    9,852

    Re: DPI Awareness per Window

    Quote Originally Posted by Eduardo- View Post
    Did you test what I said in my last post (that the awareness seems not to remain changed for long)?
    The way I read the MSDN (and some other sources) is that you call SetThreadDpiAwarenessContext, setting the awareness context to whatever you like, and be sure to save the old context ... and then you create whatever windows you want with that awareness context ... and then you put back the old context to clean-up.

    I don't see you doing that last (clean-up) step in the way you did it.

    Also, I know that VB6 creates some "under the hood" housekeeping windows (especially the IDE), so it's probably important to do that clean-up step.
    Any software I post in these forums written by me is provided "AS IS" without warranty of any kind, expressed or implied, and permission is hereby granted, free of charge and without restriction, to any person obtaining a copy. To all, peace and happiness.

  40. #40
    PowerPoster
    Join Date
    Feb 2017
    Posts
    4,995

    Re: DPI Awareness per Window

    Quote Originally Posted by Elroy View Post
    The way I read the MSDN (and some other sources) is that you call SetThreadDpiAwarenessContext, setting the awareness context to whatever you like, and be sure to save the old context ... and then you create whatever windows you want with that awareness context ... and then you put back the old context to clean-up.

    I don't see you doing that last (clean-up) step in the way you did it.

    Also, I know that VB6 creates some "under the hood" housekeeping windows (especially the IDE), so it's probably important to do that clean-up step.
    Well, the way I worked is with the context changed (forever).
    Good luck with that other approach, if you succeed please report back.
    I guess you will have to somehow hook the form's window creation to be able to change the awareness momentarily at that time. I don't see the point of going that route having a much easier alternative.

Page 1 of 2 12 LastLast

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  



Click Here to Expand Forum to Full Width