Mixed-Mode API compatibles con PPP y escalado de PPP

Compatibilidad con reconocimiento de PPP de Sub-Process

SetThreadDpiAwarenessContext permite el uso de diferentes modos de escalado de PPP dentro de un único proceso. Antes de la actualización de aniversario de Windows 10, un reconocimiento de PPP de una ventana estaba enlazado al modo de reconocimiento de PPP en todo el proceso (reconocimiento de PPP no consciente, reconocimiento de PPP del sistema o Per-Monitor reconocimiento de PPP). Pero ahora, con SetThreadDpiAwarenessContext, las ventanas de nivel superior pueden tener un modo de reconocimiento de PPP diferente al del modo de reconocimiento de PPP para todo el proceso. Esto también afecta a las ventanas secundarias, ya que siempre tendrán el mismo modo de reconocimiento de PPP que su ventana primaria.

El uso de SetThreadDpiAwarenessContext permite a los desarrolladores decidir dónde quieren centrar sus esfuerzos de desarrollo al definir el comportamiento específico de PPP para las aplicaciones de escritorio. Por ejemplo, la ventana de nivel superior principal de una aplicación se podría escalar por monitor, mientras que las ventanas secundarias de nivel superior se podrían escalar a través del escalado de mapas de bits por parte del sistema operativo.

Contexto de reconocimiento de PPP

Antes de la disponibilidad de SetThreadDpiAwarenessContext , el reconocimiento de PPP de un proceso se definió en el manifiesto del binario de la aplicación o a través de una llamada a SetProcessDpiAwareness durante la inicialización del proceso. Con SetThreadDpiAwarenessContext, cada subproceso puede tener un contexto de reconocimiento de PPP individual que puede ser diferente al del modo de reconocimiento de PPP en todo el proceso. El contexto de reconocimiento de PPP de un subproceso se representa con el tipo DPI_AWARENESS_CONTEXT y se comporta de las siguientes maneras:

  • Un subproceso puede cambiar su contexto de reconocimiento de PPP en cualquier momento.
  • Las llamadas API realizadas después de cambiar el contexto se ejecutarán en el contexto de PPP correspondiente (y se pueden virtualizar).
  • Cuando se crea una ventana, su reconocimiento de PPP se define como el reconocimiento de PPP del subproceso que realiza la llamada en ese momento.
  • Cuando se llama al procedimiento de ventana de una ventana, el subproceso cambia automáticamente al contexto de reconocimiento de PPP que estaba en uso cuando se creó la ventana.

Un escenario común para el uso de SetThreadDpiAwarenessContext es el siguiente: Comience con un subproceso que se ejecuta con un contexto (como DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE) cambie temporalmente a otro contexto (DPI_AWARENESS_CONTEXT_UNAWARE), cree una ventana y, a continuación, cambie inmediatamente el contexto del subproceso a su estado anterior. La ventana creada tendrá un contexto de PPP de DPI_AWARENESS_CONTEXT_UNAWARE, mientras que el contexto del subproceso de llamada se restaurará en DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE con una llamada posterior a SetThreadDpiAwarenessContext. En este escenario, la ventana asociada al subproceso que realiza la llamada se ejecutaría con un contexto por monitor (y, por lo tanto, no se ampliaría el mapa de bits por el sistema operativo), mientras que la ventana recién creada no sería compatible con PPP (y, por lo tanto, se ajustaría automáticamente el mapa de bits en un conjunto de pantallas en >un escalado del 100 %).

En la figura 1 se muestra cómo se ejecuta el subproceso de proceso principal con DPI_AWARENESS_CONTEXT_PER_MONITOR, cambia su contexto a DPI_AWARENESS_CONTEXT_UNAWARE y crea una nueva ventana. A continuación, la ventana recién creada se ejecuta con un contexto de reconocimiento de PPP de DPI_AWARENESS_CONTEXT_UNAWARE cada vez que se envía un mensaje a ella o se realizan llamadas API desde ella. Inmediatamente después de crear la nueva ventana, el subproceso principal se restaura en su contexto anterior de DPI_AWARENESS_CONTEXT_PER_MONITOR.

diagrama que muestra el reconocimiento de ppp por monitor en acción

Además de la compatibilidad con diferentes modos de reconocimiento de PPP dentro de un único proceso que SetThreadDpiAwarenessContext ofrece, se ha agregado la siguiente funcionalidad específica de PPP para aplicaciones de escritorio:

EnableNonClientDpiScaling

Nota

El modo de reconocimiento de PPP V2 por monitor habilita automáticamente esta funcionalidad y, por tanto, llamar a EnableNonClientDpiScaling es innecesario en las aplicaciones que lo usan.

Al llamar a EnableNonClientDpiScaling desde dentro de un controlador de WM_NCCREATE de ventana, el área que no es de cliente de una ventana de nivel superior se escala automáticamente para PPP. Si la ventana de nivel superior es compatible con PPP por monitor (ya sea porque el propio proceso es compatible con PPP por monitor o porque la ventana se creó dentro de un subproceso compatible con PPP por monitor), la barra de subtítulo, las barras de desplazamiento, los menús y las barras de menú de estas ventanas se escalarán en PPP cada vez que cambie el PPP de la ventana.

Tenga en cuenta que las áreas que no son cliente de una ventana secundaria, como las barras de desplazamiento que no son cliente de un control de edición secundario, no se escalarán automáticamente cuando se use esta API.

Nota

Se debe llamar a EnableNonClientDpiScaling desde el controlador de WM_NCCREATE.

Las API de *ForDpi
  • Varias API usadas con frecuencia, como GetSystemMetrics , no tienen ningún contexto de HWND y, por tanto, no tienen ninguna manera de deducir el reconocimiento de PPP adecuado para sus valores devueltos. Llamar a estas API desde un subproceso que se ejecuta en otro modo de reconocimiento de PPP o contexto puede devolver valores que no se escalan para el contexto del subproceso que realiza la llamada. GetSystemMetricForDpi, SystemParametersInfoForDpi y AdjustWindowRectExForDpi realizarán la misma funcionalidad que sus homólogos no conscientes de PPP, pero toman un PPP como argumento e deducen el reconocimiento de ppp desde el contexto del subproceso actual.

  • GetSystemMetricForDpi y SystemParametersInfoForDpi devolverán valores de métricas del sistema a escala de PPP y valores de parámetros del sistema de acuerdo con esta ecuación:

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

    Por lo tanto, al llamar a GetSystemMetrics (o SystemParametersInfoForDpi), mientras se ejecuta en un dispositivo con un determinado valor de PPP, se devolverá el mismo valor que sus variantes compatibles con PPP (GetSystemMetricsForDpi y SystemParametersInfoForDpi), dado el mismo valor de PPP que la entrada.

  • AdjustWindowRectExForDpi toma un HWND y calculará el tamaño necesario de un rectángulo de ventana de una manera sensible a PPP.

GetDpiForWindow
GetDpiForWindow devolverá el PPP asociado al HWND proporcionado. La respuesta dependerá del modo de reconocimiento de PPP del HWND:
Modo de reconocimiento de PPP de HWND Valor devuelto
Conscientes 96
Sistema PPP del sistema
Per-Monitor Ppp de visualización en el que se encuentra principalmente la ventana de nivel superior asociada.
(Si se proporciona una ventana secundaria, se devolverá el VALOR de PPP de la ventana primaria de nivel superior correspondiente).
GetDpiForSystem

Llamar a GetDpiForSystem es más eficaz que llamar a GetDC y GetDeviceCaps para obtener el PPP del sistema.

Cualquier componente que se pueda ejecutar en una aplicación que use el reconocimiento de PPP de subproceso no debe suponer que el PPP del sistema es estático durante el ciclo de vida del proceso. Por ejemplo, si un subproceso que se ejecuta en DPI_AWARENESS_CONTEXT_UNAWARE contexto de reconocimiento consulta el PPP del sistema, la respuesta será 96. Sin embargo, si ese mismo subproceso cambió a DPI_AWARENESS_CONTEXT_SYSTEM contexto de reconocimiento y volvió a consultar el PPP del sistema, la respuesta podría ser diferente. Para evitar el uso de un valor de PPP del sistema (y posiblemente obsoleto), use GetDpiForSystem para recuperar el PPP del sistema en relación con el modo de reconocimiento de PPP del subproceso que llama.