/// <summary> /// If possible, gets whether the window is DPI-scaled/virtualized, and gets physical and logical rects if scaled. /// Returns false if !osVersion.minWin10_1607 or if cannot get that info. /// Gets that info in a fast and reliable way. /// </summary> internal static bool GetScalingInfo_(wnd w, out bool scaled, out RECT rPhysical, out RECT rLogical) { scaled = false; rPhysical = default; rLogical = default; if (!osVersion.minWin10_1607) { return(false); } var awareness = WindowDpiAwareness(w); //fast on Win10 if (awareness is Awareness.System or Awareness.Unaware) //tested: unaware-gdi-scaled same as unaware { if (awareness == Awareness.System && Api.GetDpiForWindow(w) != System) /*fast*/ //Cannot get rLogical. It's rare and temporary, ie when the user recently changed DPI of the primary screen. //Even if this func isn't used to get rects, without this fast code could be unreliable. { Debug_.Print("w System DPI != our System DPI"); return(false); } for (; ;) { RECT r1 = w.Rect, r2, r3; //note: with ClientRect 4 times faster, but unreliable if small rect. Now fast enough. bool rectWorkaround = false; using (var u = new AwarenessContext(awareness == Awareness.System ? -2 : -1)) { if (Api.GetAwarenessFromDpiAwarenessContext(u.Previous_) != Awareness.PerMonitor) /*fast*/ //cannot get rPhysical. But let's set PM awareness and get it. Works even if this process is Unaware. { rectWorkaround = _GetRect(w, out r1); Debug_.Print("bad DPI awareness of this thread; workaround " + (rectWorkaround ? "OK" : "failed")); if (!rectWorkaround) { return(false); //unlikely. Then the caller probably will call the legacy func, it works with any DPI awareness. } } r2 = w.Rect; if (r2 == r1) { break; } } if (!rectWorkaround) { r3 = w.Rect; } else { _GetRect(w, out r3); } if (r3 != r1) { continue; //moved, resized or closed between Rect and Rect } scaled = true; rPhysical = r1; rLogical = r2; break; }
static bool _GetRect(wnd w, out RECT r) { using (var u2 = new AwarenessContext(-4)) { //per-monitor-v2 if (u2.Previous_ == 0) { r = default; return(false); } //API failed. Unlikely. Works even if this process is Unaware. r = w.Rect; } return(true); }