DPI 크기 조정 및 DPI 인식 API Mixed-Mode

Sub-Process DPI 인식 지원

SetThreadDpiAwarenessContext 를 사용하면 단일 프로세스 내에서 다양한 DPI 크기 조정 모드를 사용할 수 있습니다. Windows 10 1주년 업데이트 이전에는 창의 DPI 인식이 프로세스 차원의 DPI 인식 모드(DPI 인식, 시스템 DPI 인식 또는 Per-Monitor DPI 인식)에 바인딩되었습니다. 하지만 이제 SetThreadDpiAwarenessContext를 사용하면 최상위 창에 프로세스 수준 DPI 인식 모드와 다른 DPI 인식 모드가 있을 수 있습니다. 부모 창과 항상 동일한 DPI 인식 모드를 갖기 때문에 자식 창에도 영향을 줍니다.

SetThreadDpiAwarenessContext를 사용하면 개발자가 데스크톱 애플리케이션에 대한 DPI 관련 동작을 정의할 때 개발 작업에 집중할 위치를 결정할 수 있습니다. 예를 들어 애플리케이션의 기본 최상위 창은 모니터별로 크기를 조정할 수 있고, 운영 체제에서 비트맵 크기 조정을 통해 보조 최상위 창을 확장할 수 있습니다.

DPI 인식 컨텍스트

SetThreadDpiAwarenessContext의 가용성 이전에 프로세스의 DPI 인식은 애플리케이션 이진의 매니페스트에서 또는 프로세스 초기화 중에 SetProcessDpiAwareness 호출을 통해 정의되었습니다. SetThreadDpiAwarenessContext를 사용하면 각 스레드에 프로세스 수준 DPI 인식 모드와 다를 수 있는 개별 DPI 인식 컨텍스트가 있을 수 있습니다. 스레드의 DPI 인식 컨텍스트는 DPI_AWARENESS_CONTEXT 형식으로 표시되며 다음과 같은 방식으로 동작합니다.

  • 스레드는 언제든지 DPI 인식 컨텍스트를 변경할 수 있습니다.
  • 컨텍스트가 변경된 후 발생하는 모든 API 호출은 해당 DPI 컨텍스트에서 실행되며 가상화될 수 있습니다.
  • 창이 만들어지면 해당 DPI 인식은 해당 시간에 호출 스레드의 DPI 인식으로 정의됩니다.
  • 창에 대한 창 프로시저가 호출되면 스레드는 창을 만들 때 사용 중이던 DPI 인식 컨텍스트로 자동으로 전환됩니다.

SetThreadDpiAwarenessContext를 사용하는 일반적인 시나리오는 다음과 같습니다. 한 컨텍스트(예: DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE)로 실행되는 스레드로 시작하여 일시적으로 다른 컨텍스트(DPI_AWARENESS_CONTEXT_UNAWARE)로 전환하고 창을 만든 다음 스레드 컨텍스트를 즉시 이전 상태로 다시 전환합니다. 생성된 창에는 DPI_AWARENESS_CONTEXT_UNAWARE DPI 컨텍스트가 있으며, 호출 스레드의 컨텍스트는 SetThreadDpiAwarenessContext에 대한 후속 호출을 통해 DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE 복원됩니다. 이 시나리오에서는 호출 스레드와 연결된 창이 모니터별 컨텍스트(따라서 운영 체제에 의해 비트맵 확장되지 않음)로 실행되는 반면 새로 만든 창은 DPI를 인식하지 않으므로 디스플레이에서 자동으로 비트맵이 100% 크기 조정으로 확장 >됩니다.

그림 1에서는 주 프로세스 스레드가 DPI_AWARENESS_CONTEXT_PER_MONITOR 실행되고, 컨텍스트를 DPI_AWARENESS_CONTEXT_UNAWARE 전환하고, 새 창을 만드는 방법을 보여 줍니다. 그러면 새로 만든 창은 메시지가 디스패치되거나 API 호출이 발생할 때마다 DPI_AWARENESS_CONTEXT_UNAWARE DPI 인식 컨텍스트로 실행됩니다. 새 창을 만든 직후 주 스레드는 DPI_AWARENESS_CONTEXT_PER_MONITOR 이전 컨텍스트로 복원됩니다.

diagram showing per-monitor dpi awareness in action

SetThreadDpiAwarenessContext에서 제공하는 단일 프로세스 내에서 다양한 DPI 인식 모드에 대한 지원 외에도 데스크톱 애플리케이션에 대해 다음과 같은 DPI 관련 기능이 추가되었습니다.

EnableNonClientDpiScaling

참고

모니터별 V2 DPI 인식 모드는 이 기능을 자동으로 사용하도록 설정하므로 EnableNonClientDpiScaling을 사용하는 애플리케이션에서는 호출할 필요가 없습니다.

창의 WM_NCCREATE 처리기 내에서 EnableNonClientDpiScaling을 호출하면 최상위 창의 비 클라이언트 영역이 DPI에 대해 자동으로 크기 조정됩니다. 최상위 창이 모니터별 DPI 인식인 경우(프로세스 자체가 모니터별 DPI 인식인지 또는 모니터별 DPI 인식 스레드 내에서 창이 만들어졌기 때문인지 여부) 이러한 창의 캡션 표시줄, 스크롤 막대, 메뉴 및 메뉴 모음은 창의 DPI가 변경될 때마다 DPI 크기를 조정합니다.

자식 편집 컨트롤의 비 클라이언트 스크롤 막대와 같은 자식 창의 비 클라이언트 영역은 이 API를 사용할 때 DPI 크기가 자동으로 조정되지 않습니다.

참고

EnableNonClientDpiScalingWM_NCCREATE 처리기에서 호출되어야 합니다.

*ForDpi API
  • GetSystemMetrics와 같이 자주 사용되는 여러 API에는 HWND의 컨텍스트가 없으므로 반환 값에 대한 적절한 DPI 인식을 추론할 방법이 없습니다. 다른 DPI 인식 모드 또는 컨텍스트에서 실행되는 스레드에서 이러한 API를 호출하면 호출 스레드의 컨텍스트에 맞게 크기가 조정되지 않은 값이 반환될 수 있습니다. GetSystemMetricForDpi, SystemParametersInfoForDpiAdjustWindowRectExForDpi 는 DPI 인식에 대응하는 것과 동일한 기능을 수행하지만 DPI를 인수로 사용하고 현재 스레드의 컨텍스트에서 dpi 인식을 유추합니다.

  • GetSystemMetricForDpiSystemParametersInfoForDpi 는 다음 수식에 따라 DPI 크기 조정 시스템 메트릭 값 및 시스템 매개 변수 값을 반환합니다.

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

    따라서 특정 시스템 DPI 값이 있는 디바이스에서 실행되는 동안 GetSystemMetrics (또는 SystemParametersInfoForDpi)를 호출하면 입력과 동일한 DPI 값을 감안할 때 DPI 인식 변형(GetSystemMetricsForDpiSystemParametersInfoForDpi)과 동일한 값을 반환합니다.

  • AdjustWindowRectExForDpi 는 HWND를 사용하고 DPI에 민감한 방식으로 창 사각형의 필요한 크기를 계산합니다.

GetDpiForWindow
GetDpiForWindow 는 제공된 HWND와 연결된 DPI를 반환합니다. 대답은 HWND의 DPI 인식 모드에 따라 달라집니다.
HWND의 DPI 인식 모드 반환 값
알지 못하는 96
시스템 시스템 DPI
Per-Monitor 연결된 최상위 창이 주로 있는 디스플레이의 DPI
자식 창이 제공되면 해당 최상위 부모 창의 DPI가 반환됩니다.
GetDpiForSystem

GetDpiForSystem 호출은 GetDCGetDeviceCaps를 호출하여 시스템 DPI를 가져오는 것보다 더 효율적입니다.

하위 프로세스 DPI 인식을 사용하는 애플리케이션에서 실행될 수 있는 모든 구성 요소는 프로세스 수명 주기 동안 시스템 DPI가 정적이라고 가정해서는 안 됩니다. 예를 들어 DPI_AWARENESS_CONTEXT_UNAWARE 인식 컨텍스트에서 실행되는 스레드가 시스템 DPI를 쿼리하는 경우 대답은 96이 됩니다. 그러나 동일한 스레드가 DPI_AWARENESS_CONTEXT_SYSTEM 인식 컨텍스트로 전환되고 시스템 DPI를 다시 쿼리하는 경우 대답이 다를 수 있습니다. 캐시된(및 부실한) 시스템 DPI 값을 사용하지 않도록 하려면 GetDpiForSystem 을 사용하여 호출 스레드의 DPI 인식 모드를 기준으로 시스템 DPI를 검색합니다.