Dela via


Mixed-Mode DPI-skalning och DPI-medvetna API:er

Sub-Process stöd för DPI-medvetenhet

SetThreadDpiAwarenessContext möjliggör användning av olika DPI-skalningslägen i en enda process. Före Windows 10 Anniversary Update var ett fönsters DPI-medvetenhet bunden till det processomfattande DPI-medvetenhetsläget (DPI omedvetet, System DPI-medveten eller Per-Monitor DPI-medveten). Men nu, med SetThreadDpiAwarenessContext, kan de översta fönstren ha ett DPI-medvetenhetsläge som skiljer sig från det processomfattande DPI-medvetenhetsläget. Detta påverkar även underordnade fönster, eftersom de alltid har samma DPI-medvetenhetsläge som det överordnade fönstret.

Användningen av SetThreadDpiAwarenessContext gör det möjligt för utvecklare att bestämma var de vill fokusera sina utvecklingsinsatser när de definierar DPI-specifikt beteende för skrivbordsprogram. Till exempel kan ett programs primära toppnivåfönster anpassas per skärm medan sekundära toppnivåfönster kan skalas med bitmappsskalning utförd av operativsystemet.

DPI-medvetenhetskontexten

Före tillgängligheten för SetThreadDpiAwarenessContext definierades DPI-medvetenheten för en process antingen i manifestet för programbinärfilen eller via ett anrop till SetProcessDpiAwareness under processinitiering. Med SetThreadDpiAwarenessContextkan varje tråd ha en individuell DPI-medvetenhetskontext som kan skilja sig från det processomfattande DPI-medvetenhetsläget. DPI-medvetenhetskontexten för en tråd representeras med den DPI_AWARENESS_CONTEXT typen och fungerar på följande sätt:

  • En tråd kan få sin DPI-medvetenhetskontext ändrad när som helst.
  • Alla API-anrop som görs efter att kontexten har ändrats körs i motsvarande DPI-kontext (och kan virtualiseras).
  • När ett fönster skapas definieras dess DPI-medvetenhet utifrån DPI-medvetenheten hos den anropande tråden vid den tidpunkten.
  • När fönsterproceduren för ett fönster anropas växlas tråden automatiskt till den DPI-medvetenhetskontext som användes när fönstret skapades.

Ett vanligt scenario för användning av SetThreadDpiAwarenessContext är följande: Börja med en tråd som körs med en kontext (till exempel DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE) tillfälligt växla till en annan kontext (DPI_AWARENESS_CONTEXT_UNAWARE), skapa ett fönster och växla sedan omedelbart trådkontexten tillbaka till dess tidigare tillstånd. Det skapade fönstret har en DPI-kontext av DPI_AWARENESS_CONTEXT_UNAWARE, medan den anropande trådens kontext återställs till DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE med ett efterföljande anrop till SetThreadDpiAwarenessContext. I det här scenariot skulle fönstret som är associerat med den anropande tråden köras med en kontext per skärm (och därför inte skalas av bitmappen av operativsystemet), medan det nyligen skapade fönstret inte skulle vara DPI-medvetet (och därför automatiskt skalas av bitmappen på en skärm inställd på >100% skalning).

Bild 1 visar hur huvudprocesstråden körs med DPI_AWARENESS_CONTEXT_PER_MONITOR, växlar kontexten till DPI_AWARENESS_CONTEXT_UNAWAREoch skapar ett nytt fönster. Det nyligen skapade fönstret körs sedan med en DPI-medvetenhetskontext för DPI_AWARENESS_CONTEXT_UNAWARE när ett meddelande skickas till det eller API-anrop görs från det. Direkt efter att ha skapat det nya fönstret återställs huvudtråden till sin tidigare kontext för DPI_AWARENESS_CONTEXT_PER_MONITOR.

diagram som visar per-monitor-dpi-medvetenhet i praktiken

Förutom stöd för olika DPI-medvetenhetslägena i en enda process som SetThreadDpiAwarenessContext erbjuder har följande DPI-specifika funktioner lagts till för skrivbordsprogram:

EnableNonClientDpiScaling

Not

Per Monitor V2 DPI-medvetenhetsläget aktiverar automatiskt den här funktionen, och det är därför onödigt att anropa EnableNonClientDpiScaling i program som använder den.

Att anropa EnableNonClientDpiScaling inifrån ett fönsters WM_NCCREATE-hanterare resulterar i att området icke-klient i ett fönster på den översta nivån automatiskt skalas för DPI. Om det översta fönstret är DPI-medvetet per skärm (oavsett om själva processen är DPI-medveten per skärm eller eftersom fönstret skapades inom en DPI-medveten tråd per skärm), kommer titelraden, rullningslisten, menyerna och menyraderna i dessa fönster att skalas enligt DPI när fönstrets DPI ändras.

Observera att icke-klientområden i ett underordnat fönster, till exempel icke-klientrullningslister i en underordnad redigeringskontroll, inte skalas automatiskt när detta API används.

Anteckning

EnableNonClientDpiScaling måste anropas från WM_NCCREATE-hanteraren.

*ForDpi API:er
  • Flera api:er som används ofta, till exempel GetSystemMetrics inte har någon kontext för en HWND och därför inte har något sätt att härleda rätt DPI-medvetenhet för sina returvärden. Att anropa dessa API:er från en tråd som körs i ett annat DPI-medvetenhetsläge eller kontext kan returnera värden som inte skalas för kontexten hos den anropande tråden. GetSystemMetricForDpi, SystemParametersInfoForDpioch AdjustWindowRectExForDpi utför samma funktioner som deras DPI-ovetande motsvarigheter, men tar en DPI som argument och härleder dpi-medvetenheten från den aktuella trådens kontext.

  • GetSystemMetricForDpi och SystemParametersInfoForDpi returnerar DPI-skalade systemmåttvärden och systemparametervärden i enlighet med den här ekvationen:

    GetSystemMetrics(...) @ dpi == GetSystemMetricsForDpi(..., dpi)

    Därför kommer anrop av GetSystemMetrics (eller SystemParametersInfoForDpi), när de körs på en enhet med ett visst system-DPI-värde, att returnera samma värde som deras DPI-medvetna varianter (GetSystemMetricsForDpi och SystemParametersInfoForDpi) gör, givet samma DPI-värde som indata.

  • AdjustWindowRectExForDpi tar en HWND och beräknar den nödvändiga storleken på en fönsterrektangel på ett DPI-känsligt sätt.

GetDpiForWindow
GetDpiForWindow- returnerar DPI:n som är associerad med den angivna HWND:n. Svaret beror på DPI-medvetenhetsläget för HWND:
DPI-medvetenhetsläge för HWND Returvärde
Omedveten 96
System Systemets DPI
Per-Monitor DPI:et för visning som det associerade toppnivåfönstret främst finns på
(Om ett underordnat fönster anges returneras DPI för motsvarande överordnade fönster på den översta nivån)
GetDpiForSystem

Att anropa GetDpiForSystem är mer effektivt än att anropa GetDC och GetDeviceCaps för att hämta systemets DPI.

Alla komponenter som kan köras i ett program som använder DPI-medvetenhet under processen bör inte förutsätta att systemets DPI är statisk under processens livscykel. Om till exempel en tråd som körs under DPI_AWARENESS_CONTEXT_UNAWARE medvetenhetskontext frågar efter systemets DPI, blir svaret 96. Men om samma tråd växlade till DPI_AWARENESS_CONTEXT_SYSTEM medvetenhetskontext och frågade systemets DPI igen, kunde svaret vara annorlunda. Om du vill undvika att använda ett cachelagrat (och eventuellt inaktuellt) system-DPI-värde använder du GetDpiForSystem- för att hämta systemets DPI i förhållande till DPI-medvetenhetsläget för den anropande tråden.