Windows에서 높은 DPI Desktop 애플리케이션 개발

이 콘텐츠는 디스플레이 배율 인수(인치당 점 수 또는 DPI) 변경을 동적으로 처리하도록 데스크톱 애플리케이션을 업데이트하려는 개발자를 대상으로 하여 애플리케이션이 렌더링되는 모든 디스플레이에서 선명하게 표시되도록 합니다.

시작하려면 새 Windows 앱을 처음부터 만드는 경우 UWP(유니버설 Windows 플랫폼) 애플리케이션을 만드는 것이 좋습니다. UWP 애플리케이션은 실행 중인 각 디스플레이에 대해 자동으로 동적으로 크기 조정됩니다.

이전 Windows 프로그래밍 기술(원시 Win32 프로그래밍, Windows Forms, WPF(Windows Presentation Framework) 등)을 사용하는 데스크톱 애플리케이션 는 추가 개발자 작업 없이 DPI 크기 조정을 자동으로 처리할 수 없습니다. 이러한 작업이 없으면 애플리케이션은 많은 일반적인 사용 시나리오에서 흐리게 표시되거나 크기가 잘못 조정됩니다. 이 문서에서는 데스크톱 애플리케이션을 올바르게 렌더링하도록 업데이트하는 데 관련된 컨텍스트 및 정보를 제공합니다.

배율 인수 및 DPI 표시

디스플레이 기술이 진행됨에 따라 디스플레이 패널 제조업체는 패널의 각 물리적 공간에 점점 더 많은 픽셀을 포장했습니다. 이로 인해 현대 디스플레이 패널의 DPI(인치당 점 수)가 이전보다 훨씬 높습니다. 과거에는 대부분의 디스플레이에 실제 공간(96DPI)의 선형 인치당 96픽셀이 있었습니다. 2017년에는 DPI가 거의 300개 이상인 디스플레이를 쉽게 사용할 수 있습니다.

대부분의 레거시 데스크톱 UI 프레임워크에는 프로세스 수명 동안 디스플레이 DPI가 변경되지 않는다는 기본 제공 가정이 있습니다. 이 가정은 더 이상 true가 아닙니다. 디스플레이 DPI는 일반적으로 애플리케이션 프로세스의 수명 동안 여러 번 변경됩니다. 디스플레이 배율 인수/DPI 변경 내용이 다음과 같은 몇 가지 일반적인 시나리오입니다.

  • 각 디스플레이의 배율 인수가 다르고 애플리케이션이 한 디스플레이에서 다른 디스플레이로 이동하는 다중 모니터 설정(예: 4K 및 1080p 디스플레이)
  • 낮은 DPI 외부 디스플레이를 사용하여 높은 DPI 랩톱 도킹 및 도킹 해제(또는 그 반대)
  • 높은 DPI 랩톱/태블릿에서 낮은 DPI 디바이스로 원격 데스크톱을 통한 커넥트(또는 그 반대)
  • 애플리케이션이 실행되는 동안 디스플레이 배율 인수 설정 변경

이러한 시나리오에서 UWP 애플리케이션은 새 DPI에 대해 자동으로 다시 그리기합니다. 기본적으로 추가 개발자 작업이 없으면 데스크톱 애플리케이션은 작동하지 않습니다. DPI 변경에 응답하기 위해 이 추가 작업을 수행하지 않는 데스크톱 애플리케이션은 사용자에게 흐리게 표시되거나 크기가 잘못 조정될 수 있습니다.

DPI 인식 모드

데스크톱 애플리케이션은 DPI 크기 조정을 지원하는지 Windows에 알려야 합니다. 기본적으로 시스템은 데스크톱 애플리케이션 DPI를 인식하지 못하는 것으로 간주하고 창을 비트맵으로 늘입니다. 애플리케이션은 사용 가능한 다음 DPI 인식 모드 중 하나를 설정하여 DPI 크기 조정을 처리하는 방법을 명시적으로 Windows에 알릴 수 있습니다.

DPI 인식

DPI 인식할 수 없는 애플리케이션은 96(100%)의 고정 DPI 값으로 렌더링됩니다. 이러한 애플리케이션이 디스플레이 크기가 96DPI보다 큰 화면에서 실행될 때마다 Windows는 애플리케이션 비트맵을 예상 실제 크기로 확장합니다. 이로 인해 애플리케이션이 흐리게 표시됩니다.

시스템 DPI 인식

시스템 DPI를 인식하는 데스크톱 애플리케이션은 일반적으로 사용자 로그인 시간 기준으로 기본 연결된 모니터의 DPI를 받습니다. 초기화 중에 해당 시스템 DPI 값을 사용하여 해당 UI를 적절하게 배치합니다(컨트롤 크기 조정, 글꼴 크기 선택, 자산 로드 등). 따라서 시스템 DPI 인식 애플리케이션은 해당 단일 DPI에서 렌더링되는 디스플레이에서 Windows에 의해 DPI 크기 조정(비트맵 확장)되지 않습니다. 애플리케이션이 다른 배율 인수를 사용하여 디스플레이로 이동되거나 디스플레이 배율 인수가 변경되면 Windows는 애플리케이션의 창 크기를 비트맵으로 조정하여 흐리게 표시합니다. 실제로 시스템 DPI 인식 데스크톱 애플리케이션은 단일 디스플레이 배율 인수에서만 선명하게 렌더링되어 DPI가 변경 될 때마다 흐릿해집니다.

모니터별 및 모니터별(V2) DPI 인식

모니터별 DPI 인식 모드를 사용하도록 데스크톱 애플리케이션을 업데이트하여 DPI가 변경될 때마다 즉시 올바르게 렌더링할 수 있도록 하는 것이 좋습니다. 애플리케이션이 이 모드에서 실행하려는 것을 Windows에 보고하면 DPI가 변경될 때 Windows에서 애플리케이션을 비트맵으로 확장하지 않고 애플리케이션 창에 WM_DPICHANGED 보냅니다. 그런 다음 새 DPI에 대한 크기 조정 자체를 처리하는 것은 애플리케이션의 모든 책임입니다. 데스크톱 애플리케이션에서 사용하는 대부분의 UI 프레임워크(Windows 공용 컨트롤(comctl32), Windows Forms, Windows Presentation Framework 등) 는 자동 DPI 크기 조정을 지원하지 않으므로 개발자가 창 자체의 콘텐츠 크기를 조정하고 위치를 변경해야 합니다.

애플리케이션이 자체 등록할 수 있는 모니터별 인식에는 버전 1 및 버전 2(PMv2)의 두 가지 버전이 있습니다. PMv2 인식 모드에서 실행 중인 프로세스를 등록하면 다음이 발생합니다.

  1. DPI가 변경될 때 알림을 받는 애플리케이션(최상위 HWND 및 자식 HWND 모두)
  2. 각 디스플레이의 원시 픽셀을 표시하는 애플리케이션
  3. 애플리케이션은 Windows에서 비트맵 크기 조정되지 않습니다.
  4. 자동 비 클라이언트 영역(창 캡션, 스크롤 막대 등) Windows별 DPI 크기 조정
  5. Win32 대화 상자(CreateDialog에서) Windows에서 자동으로 DPI 크기 조정
  6. 적절한 DPI 배율로 자동으로 렌더링되는 공통 컨트롤의 테마 그리기 비트맵 자산(검사box, 단추 배경 등)입니다.

모니터별 v2 인식 모드에서 실행하는 경우 DPI가 변경되면 애플리케이션에 알림이 표시됩니다. 애플리케이션이 새 DPI에 맞게 크기를 조정하지 않으면 이전 및 새 DPI 값의 차이에 따라 애플리케이션 UI가 너무 작거나 너무 크게 표시됩니다.

참고 항목

모니터별 V1(PMv1) 인식은 매우 제한적입니다. 애플리케이션에서 PMv2를 사용하는 것이 좋습니다.

다음 표에서는 다양한 시나리오에서 애플리케이션을 렌더링하는 방법을 보여 줍니다.

DPI 인식 모드 Windows 버전 소개 애플리케이션의 DPI 보기 DPI 변경에 대한 동작
알지 못하는 해당 없음 모든 디스플레이는 96DPI입니다. 비트맵 스트레치(흐리게)
시스템 Vista 모든 디스플레이에 동일한 DPI(현재 사용자 세션이 시작된 시점의 기본 디스플레이 DPI)가 있습니다. 비트맵 스트레치(흐리게)
모니터당 8.1 애플리케이션 창이 주로 있는 디스플레이의 DPI
  • 최상위 HWND에 DPI 변경 알림이 표시됩니다.
  • UI 요소의 DPI 크기 조정이 없습니다.

모니터별 V2 Windows 10 크리에이터스 업데이트 (1703) 애플리케이션 창이 주로 있는 디스플레이의 DPI
  • 최상위 및 자식 HWND에 DPI 변경 알림이 표시됩니다.

자동 DPI 크기 조정:
  • 비 클라이언트 영역
  • 공통 컨트롤의 테마 그리기 비트맵(comctl32 V6)
  • 대화 상자(CreateDialog)

모니터당(V1) DPI 인식

모니터별 V1 DPI 인식 모드(PMv1)는 Windows 8.1에서 도입되었습니다. 이 DPI 인식 모드는 매우 제한적이며 아래에 나열된 기능만 제공합니다. 데스크톱 애플리케이션은 Windows 10 1703 이상에서 지원되는 모니터별 v2 인식 모드를 사용하는 것이 좋습니다.

모니터별 인식에 대한 초기 지원은 애플리케이션에만 다음을 제공했습니다.

  1. 최상위 HWND는 DPI 변경에 대한 알림을 받고 새로운 제안된 크기를 제공합니다.
  2. Windows는 애플리케이션 UI를 비트맵으로 확장하지 않습니다.
  3. 애플리케이션은 모든 디스플레이를 실제 픽셀로 표시합니다(가상화 참조).

Windows 10 1607 이상에서 PMv1 애플리케이션은 WM_NCCREATE 중에 EnableNonClientDpiScaling을 호출 하여 Windows가 창의 비 클라이언트 영역의 크기를 올바르게 조정하도록 요청할 수도 있습니다.

UI Framework/기술별 모니터별 DPI 크기 조정 지원

아래 표에서는 Windows 10 1703을 기준으로 다양한 Windows UI 프레임워크에서 제공하는 모니터별 DPI 인식 지원 수준을 보여 줍니다.

프레임워크/기술 지원 OS 버전 DPI 크기 조정 처리 기준 추가 참고 자료
UWP(유니버설 Windows 플랫폼) 전체 1607 UI 프레임워크 UWP(유니버설 Windows 플랫폼)
원시 Win32/Common Controls V6(comctl32.dll)
  • 모든 HWND로 전송된 DPI 변경 알림 메시지
  • 테마 그리기 자산이 공용 컨트롤에서 올바르게 렌더링됩니다.
  • 대화 상자의 자동 DPI 크기 조정
1703 애플리케이션 GitHub 샘플
Windows Forms 일부 컨트롤에 대해 모니터당 자동 DPI 크기 조정이 제한됨 1703 UI 프레임워크 Windows Forms의 높은 DPI 지원
WPF(Windows Presentation Framework) 네이티브 WPF 애플리케이션은 다른 프레임워크에서 호스트되는 WPF 크기를 DPI로 조정하고 WPF에서 호스트되는 다른 프레임워크는 자동으로 크기 조정되지 않습니다. 1607 UI 프레임워크 GitHub 샘플
GDI 없음 해당 없음 애플리케이션 GDI High-DPI 크기 조정 참조
GDI+ 없음 해당 없음 애플리케이션 GDI High-DPI 크기 조정 참조
MFC 없음 해당 없음 애플리케이션 해당 없음

기존 애플리케이션 업데이트

DPI 크기 조정을 제대로 처리하도록 기존 데스크톱 애플리케이션을 업데이트하려면 최소한 DPI 변경에 응답하도록 UI의 중요한 부분을 업데이트하도록 업데이트해야 합니다.

대부분의 데스크톱 애플리케이션은 시스템 DPI 인식 모드에서 실행됩니다. 시스템 DPI 인식 애플리케이션은 일반적으로 기본 디스플레이의 DPI(Windows 세션이 시작될 때 시스템 트레이가 있던 디스플레이)로 확장됩니다. DPI가 변경되면 Windows는 이러한 애플리케이션의 UI를 비트맵으로 확장하여 흐리게 표시되는 경우가 많습니다. 시스템 DPI 인식 애플리케이션을 모니터별 DPI 인식으로 업데이트할 때 UI 레이아웃을 처리하는 코드는 애플리케이션 초기화 중뿐만 아니라 DPI 변경 알림(Win32의 경우 WM_DPICHANGED )이 수신될 때마다 수행되도록 업데이트해야 합니다. 일반적으로 코드에서 UI의 크기를 한 번만 조정해야 한다는 가정을 다시 검토해야 합니다.

또한 Win32 프로그래밍의 경우 많은 Win32 API에는 DPI 또는 디스플레이 컨텍스트가 없으므로 시스템 DPI에 상대적인 값만 반환합니다. 코드를 통해 이러한 API 중 일부를 찾아 DPI 인식 변형으로 바꾸는 것이 유용할 수 있습니다. DPI 인식 변형이 있는 일반적인 API 중 일부는 다음과 같습니다.

단일 DPI 버전 모니터별 버전
GetSystemMetrics GetSystemMetricsForDpi
AdjustWindowRectEx AdjustWindowRectExForDpi
SystemParametersInfo SystemParametersInfoForDpi
GetDpiForMonitor GetDpiForWindow

또한 상수 DPI를 가정하는 코드베이스에서 하드 코딩된 크기를 검색하여 DPI 크기 조정을 올바르게 설명하는 코드로 바꾸는 것이 좋습니다. 다음은 이러한 모든 제안을 통합하는 예제입니다.

예시:

아래 예제에서는 자식 HWND를 만드는 간소화된 Win32 사례를 보여줍니다. CreateWindow 호출에서는 애플리케이션이 96DPI(USER_DEFAULT_SCREEN_DPI 상수)로 실행되고 있으며 단추의 크기나 위치가 더 높은 DPI에서 올바르지 않은 것으로 가정합니다.

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); 
} 

아래 업데이트된 코드는 다음을 보여줍니다.

  1. 부모 창의 DPI에 대한 자식 HWND의 위치 및 크기를 조정하는 창 만들기 코드 DPI
  2. 자식 HWND의 위치를 변경하고 크기를 조정하여 DPI 변경에 대응
  3. 하드 코딩된 크기가 제거되고 DPI 변경에 응답하는 코드로 대체됨
#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; 

시스템 DPI 인식 애플리케이션을 업데이트할 때 따라야 할 몇 가지 일반적인 단계는 다음과 같습니다.

  1. 애플리케이션 매니페스트(또는 사용된 UI 프레임워크에 따라 다른 방법)를 사용하여 프로세스를 모니터별 DPI 인식(V2)으로 표시합니다.
  2. UI 레이아웃 논리를 다시 사용할 수 있도록 하고 DPI 변경이 발생할 때 다시 사용할 수 있도록 애플리케이션 초기화 코드 밖으로 이동합니다(Windows(Win32) 프로그래밍의 경우 WM_DPICHANGED).
  3. DPI에 민감한 데이터(DPI/글꼴/크기/등)를 업데이트할 필요가 없다고 가정하는 코드를 무효화합니다. 프로세스 초기화 시 글꼴 크기 및 DPI 값을 캐시하는 것은 매우 일반적인 방법입니다. 모니터별 DPI 인식이 되도록 애플리케이션을 업데이트하는 경우 새 DPI가 발생할 때마다 DPI 중요한 데이터를 다시 평가해야 합니다.
  4. DPI 변경이 발생하면 새 DPI에 대한 비트맵 자산을 다시 로드하거나 다시 래스터화하거나 필요에 따라 현재 로드된 자산을 올바른 크기로 늘입니다.
  5. 모니터별 DPI 인식이 아닌 API에 대한 Grep를 사용하고 모니터별 DPI 인식 API(해당하는 경우)로 바꿉니다. 예: GetSystemMetrics를 GetSystemMetricsForDpi로 바꿉니다.
  6. 다중 디스플레이/다중 DPI 시스템에서 애플리케이션을 테스트합니다.
  7. 제대로 DPI 크기 조정으로 업데이트할 수 없는 애플리케이션의 최상위 창의 경우 혼합 모드 DPI 크기 조정(아래 설명)을 사용하여 시스템에서 이러한 최상위 창의 비트맵 스트레칭을 허용합니다.

혼합 모드 DPI 크기 조정(하위 프로세스 DPI 크기 조정)

모니터별 DPI 인식을 지원하도록 애플리케이션을 업데이트할 때 애플리케이션의 모든 창을 한 번의 이동으로 업데이트하는 것이 실용적이지 않거나 불가능해질 수 있습니다. 이는 단순히 모든 UI를 업데이트하고 테스트하는 데 필요한 시간과 노력 또는 실행해야 하는 모든 UI 코드를 소유하지 않기 때문일 수 있습니다(애플리케이션에서 타사 UI를 로드하는 경우). 이러한 상황에서 Windows는 UI의 더 중요한 부분을 업데이트하는 데 시간과 에너지를 집중하면서 원래 DPI 인식 모드에서 일부 애플리케이션 창(최상위 수준만)을 실행할 수 있도록 함으로써 모니터별 인식의 세계로 쉽게 진입할 수 있는 방법을 제공합니다.

다음은 기존 모드("보조 창")에서 다른 창을 실행하는 동안 모니터별 DPI 인식으로 실행하도록 기본 애플리케이션 UI(그림의 "주 창")를 업데이트하는 그림입니다.

differences in dpi scaling between awareness modes

Windows 10 1주년 업데이트(1607) 이전에는 프로세스의 DPI 인식 모드가 프로세스 전체 속성이었습니다. Windows 10 1주년 업데이트부터 이 속성은 이제 최상위 창별로 설정할 수 있습니다. (자식 창은 부모의 크기 조정 크기와 계속 일치해야 합니다.) 최상위 창은 부모가 없는 창으로 정의됩니다. 일반적으로 최소화, 최대화 및 닫기 단추가 있는 "일반" 창입니다. 하위 프로세스 DPI 인식을 위한 시나리오는 기본 UI를 업데이트하는 데 시간과 리소스를 집중하는 동안 Windows(비트맵 확장)에 따라 보조 UI를 확장하는 것입니다.

하위 프로세스 DPI 인식을 사용하도록 설정하려면 창 만들기 호출 전후에 SetThreadDpiAwarenessContext를 호출합니다. 생성된 창은 SetThreadDpiAwarenessContext를 통해 설정한 DPI 인식과 연결됩니다. 두 번째 호출을 사용하여 현재 스레드의 DPI 인식을 복원합니다.

하위 프로세스 DPI 크기 조정을 사용하면 Windows를 사용하여 애플리케이션에 대한 DPI 크기 조정을 수행할 수 있지만 애플리케이션의 복잡성을 증가시킬 수 있습니다. 이 접근 방식의 단점과 도입되는 복잡성의 특성을 이해하는 것이 중요합니다. 하위 프로세스 DPI 인식에 대한 자세한 내용은 혼합 모드 DPI 크기 조정 및 DPI 인식 API를 참조 하세요.

변경 내용 테스트

모니터별 DPI 인식이 되도록 애플리케이션을 업데이트한 후에는 애플리케이션이 혼합 DPI 환경의 DPI 변경에 올바르게 응답하도록 유효성을 검사하는 것이 중요합니다. 테스트할 몇 가지 세부 사항은 다음과 같습니다.

  1. 다양한 DPI 값의 표시 간에 애플리케이션 창을 앞뒤로 이동
  2. 다양한 DPI 값 표시 시 애플리케이션 시작
  3. 애플리케이션이 실행되는 동안 모니터의 배율 변경
  4. 기본 디스플레이로 사용하는 디스플레이를 변경하고, Windows에서 로그아웃한 다음, 다시 로그인한 후 애플리케이션을 다시 테스트합니다. 이는 하드 코딩된 크기/차원을 사용하는 코드를 찾는 데 특히 유용합니다.

일반적인 함정(Win32)

WM_DPICHANGED 제공된 제안된 사각형을 사용하지 않음

Windows에서 애플리케이션 창에 WM_DPICHANGED 메시지를 보내면 이 메시지에는 창 크기를 조정하는 데 사용해야 하는 제안된 사각형이 포함됩니다. 다음과 같이 애플리케이션에서 이 사각형을 사용하여 자체 크기를 조정하는 것이 중요합니다.

  1. 디스플레이 사이를 끌 때 마우스 커서가 창에서 동일한 상대 위치에 있는지 확인합니다.
  2. 한 DPI 변경으로 인해 후속 DPI 변경이 트리거되고 다른 DPI 변경이 트리거되는 재귀 DPI 변경 주기로 애플리케이션 창이 전환되지 않도록 방지합니다.

Windows에서 WM_DPICHANGED 메시지에 제공하는 제안된 사각형을 사용할 수 없는 애플리케이션별 요구 사항이 있는 경우 WM_GETDPISCALEDSIZE 참조하세요. 이 메시지를 사용하여 위에서 설명한 문제를 피하면서 DPI 변경이 발생한 후 사용하려는 크기를 Windows에 제공할 수 있습니다.

가상화에 대한 설명서 부족

HWND 또는 프로세스가 DPI를 인식하지 못하거나 시스템 DPI 인식으로 실행되는 경우 Windows에서 비트맵을 확장할 수 있습니다. 이 경우 Windows는 DPI에 민감한 정보를 일부 API에서 호출 스레드의 좌표 공간으로 확장하고 변환합니다. 예를 들어 DPI를 인식하지 못하는 스레드가 높은 DPI 디스플레이에서 실행되는 동안 화면 크기를 쿼리하는 경우 Windows는 화면이 96DPI 단위인 것처럼 애플리케이션에 제공된 답변을 가상화합니다. 또는 시스템 DPI 인식 스레드가 현재 사용자 세션이 시작되었을 때와 다른 DPI의 디스플레이와 상호 작용하는 경우 Windows는 원래 DPI 배율 인수에서 실행 중인 경우 HWND가 사용할 좌표 공간으로 일부 API 호출을 DPI 크기 조정합니다.

데스크톱 애플리케이션을 DPI 크기 조정으로 올바르게 업데이트하는 경우 스레드 컨텍스트에 따라 가상화된 값을 반환할 수 있는 API 호출을 알기 어려울 수 있습니다. 이 정보는 현재 Microsoft에서 충분히 문서화되지 않았습니다. DPI를 인식하지 못하거나 시스템 DPI 인식 스레드 컨텍스트에서 시스템 API를 호출하는 경우 반환 값이 가상화될 수 있습니다. 따라서 화면 또는 개별 창과 상호 작용할 때 예상되는 DPI 컨텍스트에서 스레드가 실행되고 있는지 확인합니다. SetThreadDpiAwarenessContext를 사용하여 스레드의 DPI 컨텍스트를 일시적으로 변경하는 경우 애플리케이션의 다른 위치에서 잘못된 동작이 발생하지 않도록 완료된 경우 이전 컨텍스트를 복원해야 합니다.

많은 Windows API에 DPI 컨텍스트가 없습니다.

많은 레거시 Windows API는 DPI 또는 HWND 컨텍스트를 인터페이스의 일부로 포함하지 않습니다. 따라서 개발자는 크기, 포인트 또는 아이콘과 같은 DPI에 중요한 정보의 크기 조정을 처리하기 위해 추가 작업을 수행해야 하는 경우가 많습니다. 예를 들어 LoadIcon을 사용하는 개발자는 로드된 비트맵 스트레치 아이콘을 사용하거나 대체 API를 사용하여 LoadImage와 같은 적절한 DPI에 대해 올바른 크기의 아이콘을 로드해야 합니다.

프로세스 전체 DPI 인식의 강제 재설정

일반적으로 프로세스 초기화 후에는 프로세스의 DPI 인식 모드를 변경할 수 없습니다. 그러나 창 트리의 모든 HWND에 동일한 DPI 인식 모드가 있어야 한다는 요구 사항을 위반하려고 하면 Windows에서 프로세스의 DPI 인식 모드를 강제로 변경할 수 있습니다. Windows 10 1703을 기준으로 모든 버전의 Windows에서는 HWND 트리에서 다른 HWND를 다른 DPI 인식 모드로 실행할 수 없습니다. 이 규칙을 위반하는 자식-부모 관계를 만들려고 하면 전체 프로세스의 DPI 인식을 다시 설정할 수 있습니다. 다음을 통해 트리거할 수 있습니다.

  1. 부모 창에 전달된 창이 호출 스레드와 다른 DPI 인식 모드인 CreateWindow 호출입니다.
  2. 두 창이 서로 다른 DPI 인식 모드와 연결된 SetParent 호출입니다.

아래 표에서는 이 규칙을 위반하려고 하면 어떻게 되는지 보여줍니다.

연산 Windows 8.1 Windows 10(1607 이하) Windows 10(1703 이상)
CreateWindow(In-Proc) 해당 없음 자식 상속 (혼합 모드) 자식 상속 (혼합 모드)
CreateWindow(Cross-Proc) 강제 재설정 (호출자 프로세스) 자식 상속 (혼합 모드) 강제 재설정 (호출자 프로세스)
SetParent(In-Proc) 해당 없음 강제 재설정 (현재 프로세스) 실패 (ERROR_INVALID_STATE)
SetParent(Cross-Proc) 강제 재설정 (자식 창 프로세스) 강제 재설정 (자식 창 프로세스) 강제 재설정 (자식 창 프로세스)

높은 DPI API 참조

혼합 모드 DPI 크기 조정 및 DPI 인식 API.