Share via


Mixed-Mode DPI-Skalierung und DPI-fähige APIs

Unterstützung für Sub-Process DPI-Sensibilisierung

SetThreadDpiAwarenessContext ermöglicht die Verwendung verschiedener DPI-Skalierungsmodi innerhalb eines einzelnen Prozesses. Vor dem Windows 10 Anniversary Update war die DPI-Erkennung eines Fensters an den prozessweiten DPI-Sensibilisierungsmodus (DPI nicht bekannt, System-DPI-fähig oder Per-Monitor DPI-fähig) gebunden. Mit SetThreadDpiAwarenessContext können Fenster der obersten Ebene jedoch einen DPI-Erkennungsmodus aufweisen, der sich von dem des prozessweiten DPI-Sensibilisierungsmodus unterscheidet. Dies wirkt sich auch auf untergeordnete Fenster aus, da sie immer den gleichen DPI-Sensibilisierungsmodus wie ihr übergeordnetes Fenster haben.

Durch die Verwendung von SetThreadDpiAwarenessContext können Entwickler entscheiden, wo sie sich bei der Definition des DPI-spezifischen Verhaltens für Desktopanwendungen auf ihre Entwicklungsbemühungen konzentrieren möchten. Beispielsweise kann das primäre Fenster der obersten Ebene einer Anwendung auf Monitorbasis skaliert werden, während sekundäre Fenster der obersten Ebene über Bitmapskalierung durch das Betriebssystem skaliert werden können.

Der DPI-Sensibilisierungskontext

Vor der Verfügbarkeit von SetThreadDpiAwarenessContext wurde die DPI-Erkennung eines Prozesses entweder im Manifest der Anwendungsbinärdatei oder über einen Aufruf von SetProcessDpiAwareness während der Prozessinitialisierung definiert. Mit SetThreadDpiAwarenessContext kann jeder Thread über einen individuellen DPI-Erkennungskontext verfügen, der sich von dem des prozessweiten DPI-Sensibilisierungsmodus unterscheiden kann. Der DPI-Erkennungskontext eines Threads wird mit dem typ DPI_AWARENESS_CONTEXT dargestellt und verhält sich wie folgt:

  • Der DPI-Erkennungskontext eines Threads kann jederzeit geändert werden.
  • Alle API-Aufrufe, die nach der Änderung des Kontexts erfolgen, werden im entsprechenden DPI-Kontext ausgeführt (und können virtualisiert werden).
  • Wenn ein Fenster erstellt wird, wird dessen DPI-Sensibilisierung als DPI-Sensibilisierung des aufrufenden Threads zu diesem Zeitpunkt definiert.
  • Wenn die Fensterprozedur für ein Fenster aufgerufen wird, wird der Thread automatisch in den DPI-Sensibilisierungskontext gewechselt, der beim Erstellen des Fensters verwendet wurde.

Ein häufiges Szenario für die Verwendung von SetThreadDpiAwarenessContext ist folgendes: Beginnen Sie mit einem Thread, der mit einem Kontext (z. B. DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE) ausgeführt wird, wechseln Sie vorübergehend zu einem anderen Kontext (DPI_AWARENESS_CONTEXT_UNAWARE), erstellen Sie ein Fenster, und wechseln Sie dann sofort wieder in den vorherigen Zustand. Das erstellte Fenster weist den DPI-Kontext DPI_AWARENESS_CONTEXT_UNAWARE auf, während der Kontext des aufrufenden Threads in DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE mit einem nachfolgenden Aufruf von SetThreadDpiAwarenessContext wiederhergestellt wird. In diesem Szenario wird das Fenster, das dem aufrufenden Thread zugeordnet ist, mit einem Monitorkontext ausgeführt (und daher vom Betriebssystem nicht durch Bitmap gestreckt), während das neu erstellte Fenster nicht DPI-fähig ist (und daher automatisch auf einer Aufskalierung von >100 % gestreckt wird).

Abbildung 1 veranschaulicht, wie der Standard Prozessthread mit DPI_AWARENESS_CONTEXT_PER_MONITOR ausgeführt wird, wie der Kontext in DPI_AWARENESS_CONTEXT_UNAWARE wechselt und ein neues Fenster erstellt. Das neu erstellte Fenster wird dann mit einem DPI-Erkennungskontext von DPI_AWARENESS_CONTEXT_UNAWARE ausgeführt, wenn eine Nachricht an das Fenster gesendet wird oder API-Aufrufe daraus erfolgen. Unmittelbar nach dem Erstellen des neuen Fensters wird der Standard Thread in seinem vorherigen Kontext DPI_AWARENESS_CONTEXT_PER_MONITOR wiederhergestellt.

Diagramm: Dpi-Erkennung pro Monitor in Aktion

Zusätzlich zur Unterstützung verschiedener DPI-Erkennungsmodi innerhalb eines einzelnen Prozesses, die SetThreadDpiAwarenessContext bietet, wurde die folgende DPI-spezifische Funktionalität für Desktopanwendungen hinzugefügt:

EnableNonClientDpiScaling

Hinweis

Der DPI-Erkennungsmodus pro Monitor V2 aktiviert diese Funktionalität automatisch, und der Aufruf von EnableNonClientDpiScaling ist daher in Anwendungen, die sie verwenden, unnötig.

Das Aufrufen von EnableNonClientDpiScaling innerhalb eines Fensters WM_NCCREATE Handlers führt dazu, dass der Nicht-Clientbereich eines Fensters der obersten Ebene automatisch für DPI skaliert wird. Wenn das Fenster der obersten Ebene pro Monitor DPI-fähig ist (sei es, weil der Prozess selbst dpi-fähig ist oder weil das Fenster in einem dpi-fähigen Thread pro Monitor erstellt wurde), wird die Untertitel leiste, Bildlaufleisten, Menüs und Menüleisten dieser Fenster bei jeder Dpi-Änderung des Fensters dpi skaliert.

Beachten Sie, dass Nicht-Clientbereiche eines untergeordneten Fensters, z. B. Nicht-Client-Bildlaufleisten eines untergeordneten Bearbeitungssteuerelements, bei Verwendung dieser API nicht automatisch skaliert werden.

Hinweis

EnableNonClientDpiScaling muss vom WM_NCCREATE-Handler aufgerufen werden.

Die *Fordpi-APIs
  • Mehrere häufig verwendete APIs wie GetSystemMetrics haben keinen Kontext eines HWND und haben daher keine Möglichkeit, die richtige DPI-Erkennung für ihre Rückgabewerte abzuleiten. Das Aufrufen dieser APIs aus einem Thread, der in einem anderen DPI-Sensibilisierungsmodus oder -Kontext ausgeführt wird, kann Werte zurückgeben, die für den Kontext des aufrufenden Threads nicht skaliert sind. GetSystemMetricForDpi, SystemParametersInfoForDpi und AdjustWindowRectExForDpi führen dieselbe Funktionalität wie ihre nicht fähigen DPI-Entsprechungen aus, verwenden jedoch einen DPI-Wert als Argument und ziehen die DPI-Erkennung aus dem Kontext des aktuellen Threads ab.

  • GetSystemMetricForDpi und SystemParametersInfoForDpi geben DPI-skalierte Systemmetrikwerte und Systemparameterwerte gemäß dieser Gleichung zurück:

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

    Aus diesem Grund gibt der Aufruf von GetSystemMetrics (oder SystemParametersInfoForDpi) während der Ausführung auf einem Gerät mit einem bestimmten System-DPI-Wert den gleichen Wert zurück, den ihre DPI-fähigen Varianten (GetSystemMetricsForDpi und SystemParametersInfoForDpi) bei demselben DPI-Wert wie die Eingabe aufweisen.

  • AdjustWindowRectExForDpi verwendet einen HWND und berechnet die erforderliche Größe eines Fensterrechtecks auf DPI-bezogene Weise.

GetDpiForWindow
GetDpiForWindow gibt den DPI-Wert zurück, der dem bereitgestellten HWND zugeordnet ist. Die Antwort hängt vom DPI-Erkennungsmodus des HWND ab:
DPI-Sensibilisierungsmodus von HWND Rückgabewert
Nicht bewusst 96
System System-DPI
Per-Monitor Der DPI-Wert der Anzeige, auf der sich das zugeordnete Fenster der obersten Ebene in erster Linie befindet.
(Wenn ein untergeordnetes Fenster angegeben wird, wird der DPI-Wert des entsprechenden übergeordneten Fensters der obersten Ebene zurückgegeben.)
GetDpiForSystem

Das Aufrufen von GetDpiForSystem ist effizienter als das Aufrufen von GetDC und GetDeviceCaps zum Abrufen der System-DPI.

Jede Komponente, die in einer Anwendung ausgeführt werden kann, die die DPI-Erkennung von Unterprozessen verwendet, sollte nicht davon ausgehen, dass die System-DPI während des Lebenszyklus des Prozesses statisch ist. Wenn beispielsweise ein Thread, der unter DPI_AWARENESS_CONTEXT_UNAWARE Bewusstseinskontext ausgeführt wird, die System-DPI abfragt, lautet die Antwort 96. Wenn derselbe Thread jedoch zu DPI_AWARENESS_CONTEXT_SYSTEM Bewusstseinskontext gewechselt und die System-DPI erneut abgefragt hat, könnte die Antwort anders lauten. Um die Verwendung eines zwischengespeicherten (und möglicherweise veralteten) System-DPI-Werts zu vermeiden, verwenden Sie GetDpiForSystem , um die System-DPI relativ zum DPI-Erkennungsmodus des aufrufenden Threads abzurufen.