Freigeben über


Entwicklung von Desktopanwendungen mit hoher DPI-Auflösung unter Windows

Dieser Inhalt richtet sich an Entwickler, die Desktopanwendungen aktualisieren möchten, um Skalierungsfaktoränderungen (Punkte pro Zoll oder DPI) dynamisch zu verarbeiten, sodass ihre Anwendungen auf jeder Anzeige, auf der sie gerendert werden, scharf sein können.

Wenn Sie eine neue Windows-App von Grund auf neu erstellen möchten, wird dringend empfohlen, eine Universelle Windows-Plattform (UWP) Anwendung zu erstellen. UWP-Anwendungen werden automatisch – und dynamisch – für jede Anzeige skaliert, auf der sie ausgeführt werden.

Desktopanwendungen mit älteren Windows-Programmiertechnologien (unformatierte Win32-Programmierung, Windows Forms, Windows Presentation Framework (WPF) usw.) Die DPI-Skalierung kann ohne zusätzliche Entwicklerarbeit nicht automatisch verarbeitet werden. Ohne solche Arbeit werden Anwendungen in vielen gängigen Verwendungsszenarien verschwommen oder falsch angepasst. Dieses Dokument enthält Kontext und Informationen dazu, was bei der Aktualisierung einer Desktopanwendung erforderlich ist, um ordnungsgemäß gerendert zu werden.

Skalierungsfaktor & DPI anzeigen

Da die Displaytechnologie vorangekommen ist, haben Die Hersteller von Displaypanels eine zunehmende Anzahl von Pixeln in jede Einheit des physischen Raums auf ihren Panels gepackt. Dies hat dazu geführt, dass die Punkte pro Zoll (DPI) moderner Anzeigebereiche viel höher sind als bisher. In der Vergangenheit hatten die meisten Displays 96 Pixel pro linearen Abstand (96 DPI); 2017 sind Displays mit fast 300 DPI oder höher leicht verfügbar.

Die meisten Legacy-Desktop-UI-Frameworks verfügen über integrierte Annahmen, dass sich der DPI-Wert der Anzeige während der Lebensdauer des Prozesses nicht ändert. Diese Annahme gilt nicht mehr, da sich die Anzeige-DPIs während der gesamten Lebensdauer eines Anwendungsprozesses häufig ändern. Einige häufige Szenarien, in denen sich der Skalierungsfaktor/DPI-Wert der Anzeige ändert:

  • Setups mit mehreren Monitoren, bei denen jede Anzeige einen anderen Skalierungsfaktor aufweist und die Anwendung von einer Anzeige in eine andere verschoben wird (z. B. eine 4K- und eine 1080p-Anzeige)
  • Andocken und Abdocken eines Laptops mit hohem DPI-Wert mit einem externen Display mit geringem DPI-Wert (oder umgekehrt)
  • Herstellen einer Verbindung über Remotedesktop von einem Laptop/Tablet mit hohem DPI-Wert mit einem Gerät mit geringem DPI-Wert (oder umgekehrt)
  • Ändern der Einstellungen für den Skalierungsfaktor während der Ausführung von Anwendungen

In diesen Szenarien zeichnen sich UWP-Anwendungen automatisch für den neuen DPI-Wert neu aus. Desktopanwendungen werden standardmäßig und ohne zusätzliche Entwicklerarbeit nicht verwendet. Desktopanwendungen, die diese zusätzliche Arbeit nicht ausführen, um auf DPI-Änderungen zu reagieren, werden möglicherweise für den Benutzer verschwommen oder falsch angepasst.

DPI-Sensibilisierungsmodus

Desktopanwendungen müssen Windows mitteilen, ob sie die DPI-Skalierung unterstützen. Standardmäßig berücksichtigt das System, dass Desktopanwendungen DPI-Werte nicht kennen und die Fenster durch Bitmaps gestreckt werden. Durch Festlegen eines der folgenden verfügbaren DPI-Sensibilisierungsmodi können Anwendungen Windows explizit mitteilen, wie sie die DPI-Skalierung behandeln möchten:

DPI-Unaware

Dpi-Anwendungen werden nicht mit einem festen DPI-Wert von 96 gerendert (100%). Wenn diese Anwendungen auf einem Bildschirm mit einer Anzeigeskala ausgeführt werden, die größer als 96 DPI ist, wird die Anwendungsbitmap von Windows auf die erwartete physische Größe gestreckt. Dies führt dazu, dass die Anwendung verschwommen angezeigt wird.

System-DPI-Bewusstsein

Desktopanwendungen, die systemspezifische DPI-Werte kennen, erhalten in der Regel den DPI-Wert des primären verbundenen Monitors ab dem Zeitpunkt der Benutzeranmeldung. Während der Initialisierung gestalten sie ihre Benutzeroberfläche entsprechend (Größenanpassungssteuerelemente, Auswählen von Schriftgraden, Laden von Ressourcen usw.) mithilfe dieses System-DPI-Werts. Daher werden System-DPI-fähige Anwendungen nicht von Windows skaliert (Bitmap gestreckt) und zeigen das Rendering bei diesem einzelnen DPI-Wert an. Wenn die Anwendung auf eine Anzeige mit einem anderen Skalierungsfaktor verschoben wird oder sich der Skalierungsfaktor der Anzeige andernfalls ändert, skaliert Windows die Fenster der Anwendung, sodass sie verschwommen angezeigt werden. Effektiv rendern System-DPI-fähige Desktopanwendungen nur bei einem einzigen Skalierungsfaktor der Anzeige scharf und werden immer dann verschwommen, wenn sich der DPI-Wert ändert.

Per-Monitor und Per-Monitor (V2) DPI-Sensibilisierung

Es wird empfohlen, Dass Desktopanwendungen aktualisiert werden, um den Dpi-Sensibilisierungsmodus pro Monitor zu verwenden, sodass sie sofort korrekt gerendert werden können, wenn sich der DPI-Wert ändert. Wenn eine Anwendung windows meldet, dass sie in diesem Modus ausgeführt werden soll, wird die Anwendung von Windows nicht gestreckt, wenn sich der DPI-Wert ändert, sondern WM_DPICHANGED an das Anwendungsfenster gesendet. Es liegt dann in der vollständigen Verantwortung der Anwendung, die Größe selbst für den neuen DPI-Wert zu ändern. Die meisten Benutzeroberflächenframeworks, die von Desktopanwendungen verwendet werden (allgemeine Windows-Steuerelemente (comctl32), Windows Forms, Windows Presentation Framework usw.) Die automatische DPI-Skalierung wird nicht unterstützt, sodass Entwickler die Größe ändern und den Inhalt ihrer Fenster selbst neu positionieren müssen.

Es gibt zwei Versionen von Per-Monitor Bewusstsein, dass eine Anwendung sich selbst registrieren kann: Version 1 und Version 2 (PMv2). Die Registrierung eines Prozesses als ausgeführt im PMv2-Sensibilisierungsmodus führt zu folgenden Ergebnissen:

  1. Die Anwendung, die benachrichtigt wird, wenn sich der DPI-Wert ändert (sowohl die HWNDs der obersten Ebene als auch untergeordnete HWNDs)
  2. Die Anwendung sieht die rohen Pixel jeder Anzeige.
  3. Die Anwendung, die von Windows niemals skaliert wird
  4. Automatischer Nicht-Client-Bereich (Fensterbeschriftung, Bildlaufleisten usw.) DPI-Skalierung durch Windows
  5. Win32-Dialogfelder (von CreateDialog) automatisch von Windows skaliert DPI
  6. Designgezeichnete Bitmapressourcen in allgemeinen Steuerelementen (Kontrollkästchen, Schaltflächenhintergründe usw.), die automatisch am entsprechenden DPI-Skalierungsfaktor gerendert werden

Wenn sie im Per-Monitor v2-Modus ausgeführt wird, werden Anwendungen benachrichtigt, wenn sich ihr DPI-Wert geändert hat. Wenn sich die Größe einer Anwendung für den neuen DPI-Wert nicht ändert, wird die Benutzeroberfläche der Anwendung zu klein oder zu groß angezeigt (abhängig von der Differenz in den vorherigen und neuen DPI-Werten).

Anmerkung

Per-Monitor V1 (PMv1)-Bewusstsein ist sehr begrenzt. Es wird empfohlen, dass Anwendungen PMv2 verwenden.

Die folgende Tabelle zeigt, wie Anwendungen unter verschiedenen Szenarien gerendert werden:

DPI-Sensibilisierungsmodus Windows-Version eingeführt Ansicht der DPI-Werte der Anwendung Verhalten bei DPI-Änderung
Unwissend N/A Alle Displays sind 96 DPI Bitmapdehnung (verschwommen)
System Aussicht Alle Anzeigen weisen denselben DPI-Wert auf (der DPI-Wert der primären Anzeige zum Zeitpunkt des Starts der aktuellen Benutzersitzung) Bitmapdehnung (verschwommen)
Per-Monitor 8.1 Der DPI-Wert der Anzeige, auf der sich das Anwendungsfenster in erster Linie befindet
  • HWND der obersten Ebene wird über dpi-Änderung benachrichtigt.
  • Keine DPI-Skalierung von UI-Elementen.

Per-Monitor V2 Windows 10 Creators Update (1703) Der DPI-Wert der Anzeige, auf der sich das Anwendungsfenster in erster Linie befindet
  • der obersten Ebene und untergeordneten HWNDs werden über DPI-Änderungen benachrichtigt.

Automatische DPI-Skalierung von:
  • Nicht-Clientbereich
  • Designgezeichnete Bitmaps in allgemeinen Steuerelementen (comctl32 V6)
  • Dialogfelder (CreateDialog)

Dpi-Sensibilisierung pro Monitor (V1)

Per-Monitor V1 DPI-Sensibilisierungsmodus (PMv1) wurde mit Windows 8.1 eingeführt. Dieser DPI-Sensibilisierungsmodus ist sehr begrenzt und bietet nur die unten aufgeführten Funktionen. Es wird empfohlen, dass Desktopanwendungen Per-Monitor v2-Sensibilisierungsmodus verwenden, der unter Windows 10 1703 oder höher unterstützt wird.

Die anfängliche Unterstützung für die Sensibilisierung pro Monitor bietet nur folgende Anwendungen:

  1. HWNDs der obersten Ebene werden über eine DPI-Änderung benachrichtigt und eine neue vorgeschlagene Größe bereitgestellt.
  2. Windows dehnen die Benutzeroberfläche der Anwendung nicht
  3. Die Anwendung sieht alle Anzeigen in physischen Pixeln (siehe Virtualisierung)

Unter Windows 10 1607 oder höher können PMv1-Anwendungen auch EnableNonClientDpiScaling- während WM_NCCREATE aufrufen, um anzufordern, dass Windows den Nicht-Clientbereich des Fensters ordnungsgemäß skaliert.

Pro Monitor DPI-Skalierungsunterstützung durch UI-Framework / Technologie

Die folgende Tabelle zeigt die Unterstützung für die dpi-Sensibilisierung pro Monitor, die von verschiedenen Windows UI-Frameworks ab Windows 10 1703 angeboten wird:

Framework / Technologie Unterstützen Betriebssystemversion Dpi-Skalierung verarbeitet von Weitere Lektüre
Universelle Windows-Plattform (UWP) Voll 1607 Benutzeroberflächenframework universelle Windows-Plattform (UWP)
Raw Win32/Common Controls V6 (comctl32.dll)
  • Benachrichtigungen zu DPI-Änderungen, die an alle HWNDs gesendet werden
  • Designgezeichnete Objekte werden in allgemeinen Steuerelementen ordnungsgemäß gerendert
  • Automatische DPI-Skalierung für Dialogfelder
1703 Anwendung GitHub-Beispiel-
Windows Forms Eingeschränkte automatische DPI-Skalierung pro Monitor für einige Steuerelemente 1703 Benutzeroberflächenframework Unterstützung für hohen DPI-Wert in Windows Forms
Windows Presentation Framework (WPF) Systemeigene WPF-Anwendungen skalieren WPF, die in anderen Frameworks gehostet werden, und andere in WPF gehostete Frameworks werden nicht automatisch skaliert 1607 Benutzeroberflächenframework GitHub-Beispiel-
GDI Nichts N/A Anwendung Siehe GDI High-DPI Skalierung
GDI+ Nichts N/A Anwendung Siehe GDI High-DPI Skalierung
MFC Nichts N/A Anwendung N/A

Aktualisieren vorhandener Anwendungen

Um eine vorhandene Desktopanwendung so zu aktualisieren, dass die DPI-Skalierung ordnungsgemäß verarbeitet werden kann, muss sie so aktualisiert werden, dass die wichtigen Teile der Benutzeroberfläche mindestens aktualisiert werden, um auf DPI-Änderungen zu reagieren.

Die meisten Desktopanwendungen werden im System-DPI-Sensibilisierungsmodus ausgeführt. System-DPI-fähige Anwendungen skalieren in der Regel auf den DPI-Wert der primären Anzeige (die Anzeige, auf der sich die Taskleiste zum Zeitpunkt des Starts der Windows-Sitzung befand). Wenn sich der DPI-Wert ändert, wird die Benutzeroberfläche dieser Anwendungen von Windows gestreckt, was häufig dazu führt, dass sie verschwommen sind. Bei der Aktualisierung einer System-DPI-fähigen Anwendung, um die DPI-berücksichtigung zu erhalten, muss der Code, der das UI-Layout verarbeitet, so aktualisiert werden, dass er nicht nur während der Anwendungsinitialisierung ausgeführt wird, sondern auch, wenn eine DPI-Änderungsbenachrichtigung (WM_DPICHANGED im Fall von Win32) empfangen wird. Dies umfasst in der Regel das Überarbeiten aller Annahmen im Code, dass die Benutzeroberfläche nur einmal skaliert werden muss.

Im Falle der Win32-Programmierung verfügen viele Win32-APIs nicht über einen DPI- oder Anzeigekontext, sodass nur Werte relativ zum System-DPI zurückgegeben werden. Es kann hilfreich sein, den Code zu durchlaufen, um nach einigen dieser APIs zu suchen und sie durch DPI-fähige Varianten zu ersetzen. Einige der gängigen APIs mit DPI-fähigen Varianten sind:

Einzelne DPI-Version Per-Monitor Version
GetSystemMetrics- GetSystemMetricsForDpi-
AdjustWindowRectEx AdjustWindowRectExForDpi
SystemParametersInfo- SystemParametersInfoForDpi-
GetDpiForMonitor- GetDpiForWindow-

Außerdem empfiehlt es sich, in Ihrer Codebasis nach hartcodierten Größen zu suchen, die von einem konstanten DPI-Wert ausgehen und durch Code ersetzt werden, der die DPI-Skalierung ordnungsgemäß übernimmt. Nachfolgend finden Sie ein Beispiel, das alle diese Vorschläge enthält:

Beispiel:

Das folgende Beispiel zeigt einen vereinfachten Win32-Fall zum Erstellen eines untergeordneten HWND. Der Aufruf von CreateWindow geht davon aus, dass die Anwendung mit 96 DPI (USER_DEFAULT_SCREEN_DPI Konstante) ausgeführt wird, und weder die Größe der Schaltfläche noch die Position der Schaltfläche werden bei höheren DPIs korrekt sein:

case WM_CREATE: 
{ 
    // Add a button 
    HWND hWndChild = CreateWindow(L"BUTTON", L"Click Me",  
        WS_CHILD|WS_VISIBLE|BS_PUSHBUTTON,  
        50,  
        50,  
        100,  
        50,  
        hWnd, (HMENU)NULL, NULL, NULL); 
} 

Der folgende aktualisierte Code zeigt:

  1. Die DPI-Skalierung des Fenstererstellungscodes für die Position und Größe des untergeordneten HWND für den DPI-Wert des übergeordneten Fensters
  2. Reagieren auf DPI-Änderungen durch Ändern der Position und Größenänderung des untergeordneten HWND
  3. Hartcodierte Größen wurden entfernt und durch Code ersetzt, der auf DPI-Änderungen reagiert
#define INITIALX_96DPI 50 
#define INITIALY_96DPI 50 
#define INITIALWIDTH_96DPI 100 
#define INITIALHEIGHT_96DPI 50 

// DPI scale the position and size of the button control 
void UpdateButtonLayoutForDpi(HWND hWnd) 
{ 
    int iDpi = GetDpiForWindow(hWnd); 
    int dpiScaledX = MulDiv(INITIALX_96DPI, iDpi, USER_DEFAULT_SCREEN_DPI); 
    int dpiScaledY = MulDiv(INITIALY_96DPI, iDpi, USER_DEFAULT_SCREEN_DPI); 
    int dpiScaledWidth = MulDiv(INITIALWIDTH_96DPI, iDpi, USER_DEFAULT_SCREEN_DPI); 
    int dpiScaledHeight = MulDiv(INITIALHEIGHT_96DPI, iDpi, USER_DEFAULT_SCREEN_DPI); 
    SetWindowPos(hWnd, hWnd, dpiScaledX, dpiScaledY, dpiScaledWidth, dpiScaledHeight, SWP_NOZORDER | SWP_NOACTIVATE); 
} 
 
... 
 
case WM_CREATE: 
{ 
    // Add a button 
    HWND hWndChild = CreateWindow(L"BUTTON", L"Click Me",  
        WS_CHILD|WS_VISIBLE|BS_PUSHBUTTON, 
        0, 
        0, 
        0, 
        0, 
        hWnd, (HMENU)NULL, NULL, NULL); 
    if (hWndChild != NULL) 
    { 
        UpdateButtonLayoutForDpi(hWndChild); 
    } 
} 
break; 
 
case WM_DPICHANGED: 
{ 
    // Find the button and resize it 
    HWND hWndButton = FindWindowEx(hWnd, NULL, NULL, NULL); 
    if (hWndButton != NULL) 
    { 
        UpdateButtonLayoutForDpi(hWndButton); 
    } 
} 
break; 

Beim Aktualisieren einer System-DPI-fähigen Anwendung sind einige häufige Schritte zu befolgen:

  1. Markieren Sie den Prozess je nach Monitor-DPI-fähig (V2) mithilfe eines Anwendungsmanifests (oder einer anderen Methode, abhängig von den verwendeten UI-Frameworks).
  2. Machen Sie die Ui-Layoutlogik wiederverwendbar, und verschieben Sie sie aus dem Anwendungsinitialisierungscode, sodass sie beim Auftreten einer DPI-Änderung wiederverwendet werden kann (WM_DPICHANGED im Falle der Windows-Programmierung (Win32).
  3. Ungültiger Code, der davon ausgeht, dass DPI-vertrauliche Daten (DPI/Fonts/Größen/etc.) nie aktualisiert werden müssen. Es ist sehr üblich, Schriftgrade und DPI-Werte bei der Prozessinitialisierung zwischenzuspeichern. Wenn eine Anwendung aktualisiert wird, um dpi-bezogene DPI-Werte zu berücksichtigen, müssen DPI-vertrauliche Daten bei auftreten, wenn ein neuer DPI-Wert auftritt, neu ausgewertet werden.
  4. Wenn eine DPI-Änderung auftritt, laden Sie alle Bitmapressourcen für den neuen DPI-Wert neu (oder neu rastern) oder optional die aktuell geladenen Ressourcen auf die richtige Größe.
  5. Grep für APIs, die nicht Per-Monitor DPI-fähig sind, und ersetzen sie durch Per-Monitor DPI-fähige APIs (sofern zutreffend). Beispiel: Ersetzen Sie "GetSystemMetrics" durch "GetSystemMetricsForDpi".
  6. Testen Sie Ihre Anwendung auf einem Mehrfachanzeige-/Multi-DPI-System.
  7. Verwenden Sie für alle Fenster auf oberster Ebene in Ihrer Anwendung, die Sie nicht auf eine ordnungsgemäße DPI-Skalierung aktualisieren können, die DPI-Skalierung im gemischten Modus (siehe unten), um das Dehnung von Bitmaps dieser Fenster auf oberster Ebene durch das System zu ermöglichen.

Mixed-Mode DPI-Skalierung (Sub-Process DPI-Skalierung)

Beim Aktualisieren einer Anwendung zur Unterstützung des dpi-Bewusstseins pro Monitor kann es manchmal unpraktisch oder unmöglich werden, jedes Fenster in der Anwendung einzeln zu aktualisieren. Dies kann einfach auf die Zeit und den Aufwand zurückzuführen sein, die zum Aktualisieren und Testen der gesamten Benutzeroberfläche erforderlich sind, oder weil Sie nicht über den gesamten Ui-Code verfügen, den Sie ausführen müssen (wenn Ihre Anwendung möglicherweise die Benutzeroberfläche von Drittanbietern lädt). In diesen Situationen bietet Windows eine Möglichkeit, die Welt der Sensibilisierung pro Monitor zu vereinfachen, indem Sie einige Ihrer Anwendungsfenster (nur auf oberster Ebene) im ursprünglichen DPI-Sensibilisierungsmodus ausführen können, während Sie sich auf Ihre Zeit und Energie konzentrieren, um die wichtigeren Teile Der Benutzeroberfläche zu aktualisieren.

Nachfolgend finden Sie eine Abbildung, wie dies aussehen könnte: Sie aktualisieren die Hauptanwendungsbenutzeroberfläche ("Hauptfenster" in der Abbildung), um mit dem DPI-Grad pro Monitor ausgeführt zu werden, während Sie andere Fenster im vorhandenen Modus ausführen ("Sekundäres Fenster").

Unterschiede bei der DPI-Skalierung zwischen den Sensibilisierungsmodi

Vor dem Windows 10 Anniversary Update (1607) war der DPI-Sensibilisierungsmodus eines Prozesses eine prozessweite Eigenschaft. Ab dem Windows 10 Anniversary Update kann diese Eigenschaft jetzt pro Fenster der obersten Ebene festgelegt werden. (untergeordneten Fenster müssen weiterhin mit der Skalierungsgröße ihres übergeordneten Elements übereinstimmen.) Ein Fenster auf oberster Ebene wird als Fenster ohne übergeordnetes Element definiert. Dies ist in der Regel ein "normales" Fenster mit Minimiert-, Maximierungs- und Schließen-Schaltflächen. Das Szenario, für das die Dpi-Sensibilisierung für untergeordnete Prozesse vorgesehen ist, besteht darin, dass die sekundäre Benutzeroberfläche von Windows skaliert (Bitmap gestreckt) werden soll, während Sie sich auf die Zeit und Ressourcen konzentrieren, um die primäre Benutzeroberfläche zu aktualisieren.

Rufen Sie SetThreadDpiAwarenessContext- vor und nach allen Fenstererstellungsaufrufen auf, um die DPI-Sensibilisierung von Unterprozessen zu aktivieren. Das erstellte Fenster wird dem dpi-Bewusstsein zugeordnet, das Sie über SetThreadDpiAwarenessContext festgelegt haben. Verwenden Sie den zweiten Aufruf, um den DPI-Grad des aktuellen Threads wiederherzustellen.

Während Sie die DPI-Skalierung von Unterprozessen verwenden, können Sie sich auf Windows verlassen, um einige der DPI-Skalierungen für Ihre Anwendung durchzuführen, wodurch die Komplexität Ihrer Anwendung erhöht werden kann. Es ist wichtig, dass Sie die Nachteile dieses Ansatzes und der Natur der Komplexitäten verstehen, die sie einführen. Weitere Informationen zur Dpi-Sensibilisierung unter prozessen finden Sie unter Mixed-Mode DPI-Skalierung und DPI-fähigen APIs.

Testen Ihrer Änderungen

Nachdem Sie Ihre Anwendung aktualisiert haben, damit die DPI-Werte pro Monitor beachtet werden, ist es wichtig, dass Ihre Anwendung ordnungsgemäß auf DPI-Änderungen in einer Umgebung mit gemischten DPI-Werten reagiert. Zu den zu testden Besonderheiten gehören:

  1. Verschieben von Anwendungsfenstern zwischen Anzeige unterschiedlicher DPI-Werte
  2. Starten der Anwendung auf Anzeige unterschiedlicher DPI-Werte
  3. Ändern des Skalierungsfaktors für Ihren Monitor während der Ausführung der Anwendung
  4. Ändern sie die Anzeige, die Sie als primäre Anzeige verwenden, sich von Windowsabmelden, und testen Sie ihre Anwendung dann erneut, nachdem Sie sich wieder angemeldet haben. Dies ist besonders hilfreich beim Suchen von Code, der hartcodierte Größen/Dimensionen verwendet.

Häufige Fallstricke (Win32)

Nicht das vorgeschlagene Rechteck verwenden, das in WM_DPICHANGED

Wenn Windows Ihr Anwendungsfenster eine WM_DPICHANGED Nachricht sendet, enthält diese Nachricht ein vorgeschlagenes Rechteck, das Sie zum Ändern der Größe ihres Fensters verwenden sollten. Es ist wichtig, dass Ihre Anwendung dieses Rechteck verwendet, um die Größe selbst zu ändern, wie dies geschieht:

  1. Stellen Sie sicher, dass sich der Mauscursor beim Ziehen zwischen den Anzeigen in derselben relativen Position im Fenster befindet.
  2. Verhindern Sie, dass das Anwendungsfenster in einen rekursiven DPI-Änderungszyklus wechselt, in dem eine DPI-Änderung eine nachfolgende DPI-Änderung auslöst, wodurch eine weitere DPI-Änderung ausgelöst wird.

Wenn Sie anwendungsspezifische Anforderungen haben, die verhindern, dass Sie das vorgeschlagene Rechteck verwenden, das Windows in der WM_DPICHANGED Meldung bereitstellt, lesen Sie WM_GETDPISCALEDSIZE. Diese Meldung kann verwendet werden, um Windows eine gewünschte Größe zuzuweisen, die Sie verwenden möchten, nachdem die DPI-Änderung aufgetreten ist, während die oben beschriebenen Probleme weiterhin vermieden werden.

Fehlende Dokumentation zu Virtualisierungs-

Wenn ein HWND- oder Prozess entweder als nicht erkannter DPI-Wert oder System-DPI-Wert ausgeführt wird, kann er von Windows gestreckt werden. In diesem Fall skaliert und konvertiert Windows DPI-vertrauliche Informationen aus einigen APIs in den Koordinatenbereich des aufrufenden Threads. Wenn ein DPI-Nicht-Thread beispielsweise die Bildschirmgröße abfragt, während er auf einer Bildschirmanzeige mit hohem DPI-Wert ausgeführt wird, virtualisiert Windows die Antwort der Anwendung so, als wäre der Bildschirm in 96 DPI-Einheiten enthalten. Wenn ein Thread mit System-DPI-fähiger Daten mit einem anderen DPI-Wert interagiert als beim Starten der Sitzung des aktuellen Benutzers verwendet wurde, skaliert Windows einige API-Aufrufe in den Koordinatenbereich, den der HWND verwenden würde, wenn er mit seinem ursprünglichen DPI-Skalierungsfaktor ausgeführt wurde.

Wenn Sie Ihre Desktopanwendung auf eine ordnungsgemäße DPI-Skalierung aktualisieren, kann es schwierig sein zu wissen, welche API-Aufrufe virtualisierte Werte basierend auf dem Threadkontext zurückgeben können. diese Informationen sind derzeit nicht ausreichend von Microsoft dokumentiert. Beachten Sie, dass der Rückgabewert möglicherweise virtualisiert wird, wenn Sie eine System-API aus einem DPI-unaware- oder system-DPI-fähigen Threadkontext aufrufen. Stellen Sie daher sicher, dass ihr Thread im dpi-Kontext ausgeführt wird, den Sie bei der Interaktion mit dem Bildschirm oder einzelnen Fenstern erwarten. Achten Sie beim vorübergehenden Ändern des DPI-Kontexts eines Threads mit SetThreadDpiAwarenessContextdarauf, den alten Kontext wiederherzustellen, wenn Sie fertig sind, um ein falsches Verhalten an anderer Stelle in Ihrer Anwendung zu vermeiden.

Viele Windows-APIs verfügen nicht über einen DPI-Kontext

Viele ältere Windows-APIs enthalten keinen DPI- oder HWND-Kontext als Teil ihrer Schnittstelle. Daher müssen Entwickler häufig zusätzliche Aufgaben ausführen, um die Skalierung vertraulicher Informationen mit DPI-Werten wie Größen, Punkten oder Symbolen zu bewältigen. Beispielsweise müssen Entwickler, die LoadIcon- verwenden, entweder bitmapdehnungsgeladene Symbole oder alternative APIs verwenden, um Symbole mit korrekter Größe für den entsprechenden DPI-Wert zu laden, z. B. LoadImage-.

erzwungene Zurücksetzung des prozessweiten DPI-Bewusstseins

Im Allgemeinen kann der DPI-Sensibilisierungsmodus des Prozesses nach der Prozessinitialisierung nicht geändert werden. Windows kann jedoch den DPI-Sensibilisierungsmodus Ihres Prozesses forcibly ändern, wenn Sie versuchen, die Anforderung zu unterbrechen, dass alle HWNDs in einer Fensterstruktur den gleichen DPI-Sensibilisierungsmodus aufweisen. In allen Versionen von Windows ab Windows 10 1703 ist es nicht möglich, unterschiedliche HWNDs in einer HWND-Struktur in verschiedenen DPI-Sensibilisierungsmodi auszuführen. Wenn Sie versuchen, eine untergeordnete Beziehung zu erstellen, die diese Regel umbricht, kann der DPI-Grad des gesamten Prozesses zurückgesetzt werden. Dies kann ausgelöst werden durch:

  1. Ein CreateWindow-Aufruf, bei dem das übergebene übergeordnete Fenster einen anderen DPI-Sensibilisierungsmodus aufweist als der aufrufende Thread.
  2. Ein SetParent-Aufruf, bei dem die beiden Fenster unterschiedlichen DPI-Sensibilisierungsmodi zugeordnet sind.

Die folgende Tabelle zeigt, was passiert, wenn Sie versuchen, diese Regel zu verletzen:

Operation Windows 8.1 Windows 10 (1607 und früher) Windows 10 (1703 und höher)
CreateWindow (In-Proc) N/A Untergeordnetes Element erbt (gemischter Modus) Untergeordnetes Element erbt (gemischter Modus)
CreateWindow (Cross-Proc) erzwungene Zurücksetzung (prozess des Aufrufers) Untergeordnetes Element erbt (gemischter Modus) erzwungene Zurücksetzung (prozess des Aufrufers)
SetParent (In-Proc) N/A Erzwungenes Zurücksetzen (des aktuellen Prozesses) Fail (ERROR_INVALID_STATE)
SetParent (Cross-Proc) erzwungene Zurücksetzung (des Prozesses des untergeordneten Fensters) erzwungene Zurücksetzung (des Prozesses des untergeordneten Fensters) erzwungene Zurücksetzung (des Prozesses des untergeordneten Fensters)

API-Referenz für hohe DPI-Werte

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