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.
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.
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.
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.
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.
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.
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.
- 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.
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.
Originally Posted by vb6forever
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.
- 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.
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.
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:
(Also as a PNG in a ZIP attachment so you can see it better, if you need to.)
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.
- 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 callingGetSystemMetricsForDpi() and not ever for direct use. The metrics themselves have separate X and Y values.
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.
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.
True, but that's a scaling factor only meant to be used in callingGetSystemMetricsForDpi() 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?
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:
(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.
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.
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.
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.
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.
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:
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.
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.
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.
@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.
@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
Last edited by Eduardo-; Oct 26th, 2021 at 01:45 PM.
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.
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.