Open vsfeedback opened 1 month ago
Can you please share a minimal repro for the same.
@harshit7962
The demo. 1 shared library, 1 wpf app to call it. 1 vsto addin to call it.
Questions? dont hesitate!
Jurgen aka keepITcool
How does this work? After 4 days there's 1 thumb from @lindexi. Nothing else. After all the work I put into this, I'm not impressed tbh.
@xlsupport I am looking your code, but I do not know why ...
@lindexi Can you please elaborate. Why what? There appear to be some static variables in HwndSource (set from code in utils I believe). I also believe those are set using manifest's (win8.1) ProcessAwareness. And they seems to have priority over laters calls to ContextAwarenss. I'm a vb hack, c# is not my mothertongue ;-)
@xlsupport Sorry, this problem is too complicated for me...
@harshit7962 Sorry to be pushing, but can this be assigned to someone to investigate?
Let me make it easier for you by pointing at (one of) the culprits...
HwndTarget.cs line 296
public override Visual RootVisual
{
[SecurityCritical]
[UIPermission(SecurityAction.LinkDemand, Window = UIPermissionWindow.AllWindows)]
set
{
base.RootVisual = value;
if (value != null)
{
if (IsProcessPerMonitorDpiAware == true)
{
DpiFlags dpiFlags = DpiUtil.UpdateDpiScalesAndGetIndex(_currentDpiScale.PixelsPerInchX, _currentDpiScale.PixelsPerInchY);
DpiScale newDpiScale = new DpiScale(UIElement.DpiScaleXValues[dpiFlags.Index], UIElement.DpiScaleYValues[dpiFlags.Index]);
RootVisual.RecursiveSetDpiScaleVisualFlags(new DpiRecursiveChangeArgs(dpiFlags, RootVisual.GetDpi(), newDpiScale));
}
UnsafeNativeMethods.NotifyWinEvent(1879048191, _hWnd.MakeHandleRef(this), 0, 0);
}
}
}
Calls this from HwndTarget.cs line 246
internal static bool? IsProcessPerMonitorDpiAware
{
get
{
if (ProcessDpiAwareness.HasValue)
{
return ProcessDpiAwareness.Value == MS.Win32.NativeMethods.PROCESS_DPI_AWARENESS.PROCESS_PER_MONITOR_DPI_AWARE;
}
return null;
}
}
But that will return False when Wpf is hosted in a VSTO controlled domain., where the Process is PROCESS_SYSTEM_AWARE, and the dev only has control over the AwarenessContext.
Why this does not call GetDpiAwarenessContextForProcess (available since build 1803 / 10.0.17134 !!!) is beyond me. It just doesn't make sense... And if that breaks compatibility then what about a method to modify the Matrices in HwndSource and HwndTarget. Similar to SetRootDpi which updates the UIElement, but at the Hwnd level... call it SetHwndDpi?
@xlsupport Could you format the code?
@xlsupport - Due to other high priority work that the team is involved in, we won't be able to look into this issue right away. Appreciate your patience on this.
@xlsupport - apologies for not keeping a close eye on it. As mentioned above we are a bit occupied with some other priority tasks and would take it up as we get the width to do so. Regarding the tag "waiting-author-feedback" not getting removed, we have it automated and due the mismatch in username it did not get out automatically.
Would like to thank you for your detailed investigation and would appreciate your patience on this. Will mark it as investigate as of now.
@pchaurasia14 please check your own SLA. I hope you appreciate my patience is wearing thin.
@xlsupport The IsProcessPerMonitorDpiAware
property will use the value of ProcessDpiAwareness
. And the value of ProcessDpiAwareness
is from GetProcessDpiAwareness
method, see
The GetProcessDpiAwareness
method will call the GetProcessDpiAwareness
, which from Shcore.dll
.
But I do not know what is the difference between GetDpiAwarenessContextForProcess
and GetProcessDpiAwareness
.
Can you sure the GetDpiAwarenessContextForProcess
can return the correct value?
@lindexi As i said in my 1st post... GetProcessDpiAwareness is win81 old hat. See https://learn.microsoft.com/en-us/windows/win32/hidpi/dpi-awareness-context . DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2 introduced the whole concept of a Thread DpiAwarenessContext. And when my DpiHelper can catch the DPIChanged events, there's zero reasons why Hwndsource can't.
Maybe we can try call the GetDpiAwarenessContextForProcess
in SafeNativeMethods.GetProcessDpiAwareness
, see
@lindexi You stated you do not know the difference between ProcessAwareness and ProcessAwarenessContext, but you are on the right track! But HwndTarget.cs and HwndSource are pretty fundamental classes... so can you please help get this assigned to someone with the knowledge and overview this requires?
I also noted that DPI_AWARENESS_CONTEXT_UNAWARE_GDISCALED, which has been been defined in windef.h since October 2018 (win10 version 1809) is missing in src.
Can't find it in src/Microsoft.DotNet.Wpf/src/Shared/MS/Win32/NativeMethodsCLR.cs Can't find it in src/Microsoft.DotNet.Wpf/src/Shared/MS/Utility/DpiAwarenessContext/DpiAwarenessContextValue.cs (Last modfied 5 years ago)
It's not relevant to my scenario, but just a reminder people don't change these lightly. And there must be fallbacks for earlier environments.
HTH, and waiting for my issue to be assigned! Jurgen.
so can you please help get this assigned to someone with the knowledge and overview this requires?
Waiting Harshit
@harshit & @pchaurasia14 bump!
@xlsupport - Sorry, still no progress. Unfortunately, we won't be able to prioritize this right now due to ongoing .NET 9 release commitments.
@HARSHIT & @pchaurasia14 One month later...
This issue has been moved from a ticket on Developer Community.
[severity:It’s more difficult to complete my work]
[severity:it's a BUG]
My WPF needs to handle Multimonitor DPI inside VSTO Office addin.
Since my WPF is hosted, I can’t control the manifest of the host app and access is denied when I try to set the ProcessDpiAwareness in code.
So what I need to do:
set the Process/Thread DPIAwarenessContext.
set a HwndSourceHook, catch the WM_DPICHANGED and forward dpi and size to WPF.
set SetRootDPI on my Window.
set LayoutTransform to Window
set LayoutTransform To Window’s child.
It’s cumbersome but it works, EXCEPT for Popups and Tooltips that end up in the wrong location (or monitor) and in the wrong scale.
What happens:
In hosted WPF the HwndSource is ‘stuck’ to SystemDPI. The layout transforms have to bridge the delta between actual dpi and system dpi. But Popups and Tooltips don’t fall within the Window’s visual tree and require workrounds. For generic Tooltips I can bind to the ancestor Window’s LayoutTransform. But some will be defined in resources used for a DataGrid and cannot locate the ancestor Window.
Also Window location/sizes (including Min/Max Height/Width) are in SystemDPI and require manipulation. Not hard, but contrary to WPF design philosophy.
From a layman’s perspective you’d think all this is needlessly difficult.
There should be no need for hooking, setrootdpi, layouttransforms and the Popup problems/workarounds.
The solution?
When I set the DpiContextAwareness the HwndSource SHOULD handle DpiChanges itself. Afaik for HwndSource the (windows 8.1) ProcessAwareness is dominant, and in a hosted environment the (win10) AwarenessContext is ignored. If HwndSource knows the correct DPI then PopupRoot will know as well.
Microsoft please fix this!
I have a demo project. It’s currently VB, but easily changed to C#. And it also has a good workaround for the Modeless WPF input focus issue. Another WPF bug/design feature that never gets addressed.
Kind regards,
Jurgen (aka keepITcool)
Original Comments
Feedback Bot on 7/17/2024, 07:30 AM:
(private comment, text removed)
Original Solutions
(no solutions)