Compartilhar via


Desenvolvimento de Aplicativos de Área de Trabalho de Alta DPI no Windows

Este conteúdo é direcionado a desenvolvedores que desejam atualizar aplicativos da área de trabalho do Windows para tratar dinamicamente as alterações no fator de escala da tela (pontos por polegada, ou DPI), permitindo que seus aplicativos sejam nítidos em qualquer tela em que forem renderizados.

Para iniciar, se estiver criando um novo aplicativo do Windows do zero, é altamente recomendável criar um aplicativo da Plataforma Universal do Windows (UWP). Os aplicativos UWP são dimensionados automática e dinamicamente para cada tela em que estão sendo executados.

Aplicativos da área de trabalho do Windows que usam tecnologias de programação mais antigas (programação Win32 bruta, Windows Forms, Windows Presentation Framework (WPF), etc.) não são capazes de tratar automaticamente o ajuste de DPI sem trabalho adicional do desenvolvedor. Sem esse trabalho, os aplicativos aparecerão desfocados ou com o tamanho incorreto em muitos cenários de uso comum. Este documento fornece contexto e informações sobre o que está envolvido na atualização de um aplicativo da área de trabalho do Windows para que seja renderizado corretamente.

Fator de Escala da Tela & DPI

À medida que a tecnologia de exibição progrediu, os fabricantes de telas passaram a colocar um número maior de pixels em cada unidade de espaço físico em seus painéis. Isso fez com que os pontos por polegada (DPI) das telas modernas fossem muito mais altos do que eram historicamente. No passado, a maioria das telas tinha 96 pixels por polegada linear de espaço físico (96 DPI); em 2017, telas com quase 300 DPI ou mais estavam prontamente disponíveis.

A maioria das estruturas da IU herdadas para desktop pressupõe de forma interna que o DPI da tela não será alterado durante o tempo de vida do processo. Essa suposição não é mais verdadeira, pois os DPIs de exibição normalmente são alterados várias vezes durante o tempo de vida de um processo de aplicativo. Alguns cenários comuns em que o DPI/fator de escala da tela é alterado são:

  • Configurações com várias telas em que cada tela tem um fator de escala diferente e o aplicativo é movido de uma tela para outra (como uma tela 4K e 1080p)
  • Encaixando e desencaixando um laptop de alto DPI com um vídeo externo de baixo DPI (ou vice-versa)
  • Conectando-se por meio da Área de Trabalho Remota de um laptop/tablet de alto DPI a um dispositivo de baixo DPI (ou vice-versa)
  • Realizando uma alteração nas configurações do fator de escala de exibição enquanto os aplicativos estão em execução

Nesses cenários, os aplicativos UWP são redesenhados automaticamente para um novo DPI. Por padrão, e sem trabalho adicional do desenvolvedor, os aplicativos da área de trabalho do Windows não o fazem. Os aplicativos da área de trabalho do Windows que não fazem esse trabalho extra para responder às alterações de DPI podem aparecer desfocados ou com tamanho incorreto para o usuário.

Modo de Reconhecimento de DPI

Os aplicativos da área de trabalho do Windows devem informar ao Windows se dão suporte ao ajuste de DPI. Por padrão, o sistema considera os aplicativos da área de trabalho do Windows sem reconhecimento de DPI e amplia suas janelas com bitmap. Ao definir um dos seguintes modos de reconhecimento de DPI disponíveis, os aplicativos podem informar explicitamente ao Windows como desejam lidar com o ajuste de DPI:

Sem reconhecimento de DPI

Os aplicativos sem reconhecimento de DPI renderizam em um valor de DPI fixo de 96 (100%). Sempre que esses aplicativos forem executados em uma tela com uma escala de exibição maior que 96 DPI, o Windows ampliará o bitmap do aplicativo conforme o tamanho físico esperado. Isso faz com que o aplicativo apareça desfocado.

Reconhecimento da DPI do sistema

Os aplicativos da área de trabalho do Windows com reconhecimento de DPI do sistema normalmente recebem o DPI do monitor principal conectado no momento em que o usuário entra. Durante a inicialização, eles organizam a interface do usuário adequadamente (controles de dimensionamento, escolha de tamanhos de fonte, carregamento de ativos etc.) usando esse valor de DPI do sistema. Dessa forma, os aplicativos com reconhecimento de DPI do sistema não são dimensionados em DPI (bitmap ampliado) pelo Windows em telas renderizadas com esse único DPI. Quando o aplicativo é movido para uma tela com um fator de escala diferente, ou se o fator de escala da tela for alterado de outra forma, o Windows dimensionará em bitmap as janelas do aplicativo, fazendo com que elas pareçam borradas. Efetivamente, os aplicativos de área de trabalho do Windows com reconhecimento de DPI do sistema só são renderizados com nitidez em um único fator de escala de exibição, ficando borrados sempre que o DPI é alterado.

Reconhecimento de DPI por Monitor e por Monitor (V2)

Recomenda-se que os aplicativos da área de trabalho do Windows sejam atualizados para usar o modo de reconhecimento de DPI por monitor, permitindo que sejam imediatamente renderizados corretamente sempre que o DPI for alterado. Quando um aplicativo relata ao Windows que deseja ser executado nesse modo, o Windows não ampliará o bitmap do aplicativo quando o DPI for alterado, enviando WM_DPICHANGED para a janela do aplicativo. Em seguida, é de total responsabilidade do aplicativo tratar do redimensionamento para o novo DPI. A maioria das estruturas da IU usadas por aplicativos da área de trabalho do Windows (controles comuns do Windows (comctl32), Windows Forms, Windows Presentation Framework, etc.) não dão suporte ao ajuste de DPI automático, exigindo que os desenvolvedores redimensionem e reposicionem o conteúdo de suas janelas por conta própria.

Existem duas versões do reconhecimento Por Monitor que um aplicativo pode registrar: versão 1 e versão 2 (PMv2). O registro de um processo como executado no modo de reconhecimento PMv2 resulta em:

  1. O aplicativo sendo notificado quando o DPI for alterado (tanto os HWNDs de nível superior quanto os elementos filhos)
  2. O aplicativo vê os pixels brutos de cada tela
  3. O aplicativo nunca é dimensionado em bitmap pelo Windows
  4. Área automática não-cliente (legenda de janelas, barras de rolagem etc.) Ajuste de DPI pelo Windows
  5. As caixas de diálogo Win32 (de CreateDialog) são automaticamente dimensionados em DPI pelo Windows
  6. Ativos de bitmap desenhados por tema em controles comuns (caixas de seleção, planos de fundo de botões etc.) sendo renderizados automaticamente no fator de escala de DPI apropriado

Ao executar no modo de Reconhecimento Por Monitor v2 Awareness, os aplicativos são notificados quando seu DPI é alterado. Se um aplicativo não redimensionar para o novo DPI, a interface do usuário do aplicativo aparecerá muito pequena ou muito grande (dependendo da diferença entre os valores de DPI anterior e novo).

Observação

O reconhecimento Por Monitor V1 (PMv1) é muito limitado. Recomenda-se que os aplicativos usem o PMv2.

A tabela a seguir mostra como os aplicativos serão renderizados em diferentes cenários:

Modo de Reconhecimento de DPI Introduzida a Versão para Windows Exibição de DPI do aplicativo Comportamento ao alterar o DPI
Sem reconhecimento N/D Todas as telas têm 96 DPI Ampliação do bitmap (embaçado)
Sistema Vista Todos as telas têm o mesmo DPI (o DPI da tela principal no momento em que a sessão atual do usuário foi iniciada) Ampliação do bitmap (embaçado)
Por Monitor 8.1 O DPI da tela em que a janela do aplicativo está localizada principalmente
  • O HWND de Nível superior é notificado sobre a alteração do DPI
  • Não há ajuste de DPI de nenhum elemento da interface do usuário.

Por Monitor V2 Atualização do Windows 10 para Criadores (1703) O DPI da tela em que a janela do aplicativo está localizada principalmente
  • Os HWNDs filhos e nível superior são notificados sobre a alteração de DPI

Ajuste de DPI automático de:
  • Área não-cliente
  • Bitmaps desenhados por tema em controles comuns (comctl32 V6)
  • Diálogos (CreateDialog)

Reconhecimento de DPI Por Monitor (V1)

O modo de reconhecimento de DPI Por Monitor V1 (PMv1) foi introduzido com o Windows 8.1. Esse modo de reconhecimento de DPI é muito limitado e oferece apenas a funcionalidade listada abaixo. Recomenda-se que os aplicativos da área de trabalho do Windows usem o modo de reconhecimento Por Monitor v2, com suporte no Windows 10 1703 ou superior.

O suporte inicial para o reconhecimento por monitor oferecia apenas os seguintes aplicativos:

  1. Os HWNDs de nível superior são notificados sobre uma alteração de DPI e fornecem um novo tamanho sugerido
  2. O Windows não ampliará o bitmap da interface do usuário do aplicativo
  3. O aplicativo vê todas as telas em pixels físicos (consulte virtualização)

No Windows 10 1607 ou superior, os aplicativos PMv1 também podem chamar EnableNonClientDpiScaling durante WM_NCCREATE para solicitar que o Windows escale corretamente a área não cliente da janela.

Suporte ao Ajuste de DPI Por Monitor por Tecnologia / Estrutura da IU

A tabela abaixo mostra o nível de reconhecimento de DPI por monitor oferecido por várias estruturas da IU do Windows a partir do Windows 10 1703:

Estrutura / Tecnologia Suporte Versão do SO Ajuste de DPI tratado por Leitura Adicional
UWP (Plataforma Universal do Windows) Completo 1607 Estrutura da IU UWP (Plataforma Universal do Windows)
Controles Comuns/Win32 Brutos V6 (comctl32.dll)
  • Mensagens de notificação de alteração de DPI enviadas a todos os HWNDs
  • Os ativos desenhados por tema são renderizados corretamente em controles comuns
  • Ajuste de DPI automático para caixas de diálogo
1703 Aplicativo Amostra do GitHub
Windows Forms Ajuste de DPI automático por monitor limitado para alguns controles 1703 Estrutura da IU High DPI Support in Windows Forms (Suporte a alto DPI no Windows Forms)
Windows Presentation Framework (WPF) Os aplicativos nativos do WPF ajustarão a escala de DPI do WPF hospedado em outras estruturas e outras estruturas hospedadas no WPF não serão escaladas automaticamente 1607 Estrutura da IU Amostra do GitHub
GDI Nenhum N/D Aplicativo Consulte Ajuste de DPI de GDI Alto
GDI+ Nenhum N/D Aplicativo Consulte Ajuste de DPI de GDI Alto
MFC Nenhum N/D Aplicativo N/D

Atualizando os Aplicativos Existentes

Para atualizar um aplicativo de área de trabalho existente a fim de tratar adequadamente o ajuste de DPI, ele precisa ser atualizado de forma que, no mínimo, as partes importantes da interface do usuário sejam atualizadas para responder às alterações de DPI.

A maioria dos aplicativos da área de trabalho do Windows é executada no modo de reconhecimento de DPI do sistema. Os aplicativos com reconhecimento de DPI do sistema normalmente são escalados para o DPI da tela principal (a tela em que a bandeja do sistema estava localizada no horário em que a sessão do Windows foi iniciada). Quando o DPI é alterado, o Windows amplia o bitmap da interface do usuário desses aplicativos, o que geralmente resulta em desfoque. Ao atualizar um aplicativo com reconhecimento de DPI do Sistema para que ele passe a ter reconhecimento de DPI por monitor, o código que trata do layout da interface do usuário precisa ser atualizado de modo que ele seja executado não apenas durante a inicialização do aplicativo, mas também sempre que uma notificação de alteração de DPI (WM_DPICHANGED no caso do Win32) for recebida. Normalmente, isso envolve a revisão de quaisquer suposições no código de que a interface do usuário só precisa ser escalada uma vez.

Além disso, no caso da programação Win32, muitas APIs Win32 não têm nenhum contexto de exibição ou DPI, portanto, só retornarão valores relativos ao DPI do sistema. Pode ser útil pesquisar seu código através do grep para procurar algumas dessas APIs e substituí-las por variantes com reconhecimento de DPI. Algumas das APIs comuns que têm variantes com reconhecimento de DPI são:

Versão de DPI único Versão Por Monitor
GetSystemMetrics GetSystemMetricsForDpi
AdjustWindowRectEx AdjustWindowRectExForDpi
SystemParametersInfo SystemParametersInfoForDpi
GetDpiForMonitor GetDpiForWindow

Também é uma boa ideia pesquisar os tamanhos embutidos em código em sua base de código que assumem um DPI constante, substituindo-os por códigos que considerem corretamente o ajuste de DPI. Abaixo está um exemplo que incorpora todas essas sugestões:

Exemplo:

O exemplo abaixo mostra um caso simplificado de criação de um HWND filho no Win32. A chamada para CreateWindow pressupõe que o aplicativo está sendo executado a 96 DPI (constante USER_DEFAULT_SCREEN_DPI), e nem o tamanho nem a posição do botão estarão corretos em DPIs mais altos:

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

O código atualizado abaixo mostra:

  1. O código de criação de janelas ajusta o DPI da posição e do tamanho do HWND filho para o DPI de sua janela pai
  2. Respondendo à alteração de DPI reposicionando e redimensionando o elemento filho HWND
  3. Os tamanhos embutidos em código foram removidos e substituídos por códigos que respondem a alterações de 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; 

Ao atualizar um aplicativo com reconhecimento de DPI do sistema, algumas etapas comuns a serem seguidas são:

  1. Marque o processo como com reconhecimento de DPI por monitor (V2) usando um manifesto de aplicativo (ou outro método, dependendo da(s) estrutura(s) de IU usada(s)).
  2. Torne a lógica de layout da interface do usuário reutilizável e mova-a para fora do código de inicialização do aplicativo, de modo que possa ser reutilizada quando ocorrer uma alteração de DPI (WM_DPICHANGED no caso da programação do Windows (Win32)).
  3. Invalide qualquer código que pressuponha que os dados confidenciais de DPI (DPI/fontes/tamanhos/etc.) nunca precisem ser atualizados. É uma prática muito comum armazenar em cache os tamanhos de fonte e os valores de DPI na inicialização do processo. Ao atualizar um aplicativo para que ele se torne com reconhecimento de DPI por monitor, os dados confidenciais de DPI devem ser reavaliados sempre que um novo DPI for encontrado.
  4. Quando ocorrer uma alteração de DPI, recarregue (ou rasterize) todos os ativos de bitmap para o novo DPI ou, opcionalmente, amplie o bitmap dos ativos carregados atualmente para o tamanho correto.
  5. Procure por APIs que não estejam com reconhecimento de DPI por Monitor e substitua-as por APIs com reconhecimento de DPI por Monitor (em que for aplicável). Exemplo: substitua GetSystemMetrics por GetSystemMetricsForDpi.
  6. Teste seu aplicativo em um sistema com várias telas/multi-DPI.
  7. Para quaisquer janelas principais no seu aplicativo que não possam ser atualizadas para a escala de DPI, use o ajuste de DPI de modo misto (descrito abaixo) para permitir a ampliação do bitmap dessas janelas principais pelo sistema.

Ajuste de DPI de Modo Misto (Ajuste de DPI do Subprocesso)

Ao atualizar um aplicativo para dar suporte ao reconhecimento de DPI por monitor, às vezes pode ser impraticável ou impossível atualizar todas as janelas do aplicativo de uma só vez. Isso pode ser simplesmente devido ao tempo e ao esforço necessários para atualizar e testar toda a interface do usuário ou porque você não possui todo o código da interface do usuário que precisa executar (se o seu aplicativo talvez carregue a interface do usuário de terceiros). Nessas situações, o Windows oferece uma maneira de facilitar a entrada no mundo do reconhecimento por monitor, permitindo que você execute algumas das janelas do aplicativos (somente as principais) no modo original de reconhecimento de DPI, enquanto foca seu tempo e energia na atualização das partes mais importantes da interface do usuário.

Abaixo está uma ilustração de como isso poderia ser: você atualiza a interface do usuário do aplicativo principal ("Janela principal" na ilustração) para executar com reconhecimento de DPI por monitor enquanto executa outras janelas no modo existente ("Janela secundária").

differences in dpi scaling between awareness modes

Antes da Atualização de Aniversário do Windows 10 (1607), o modo de reconhecimento de DPI de um processo era uma propriedade de todo o processo. A partir da Atualização de Aniversário do Windows 10, essa propriedade agora pode ser definida como uma janela principal. (As janelas Filho devem continuar correspondendo ao tamanho da escala do seu pai.) Uma janela principal é definida como uma janela sem pai. Normalmente, trata-se de uma janela "normal" com botões minimizar, maximizar e fechar. O cenário para o qual o reconhecimento de DPI do subprocesso é destinado é o de ter a interface do usuário secundária escalada pelo Windows (bitmap ampliado) enquanto você foca seu tempo e seus recursos na atualização da interface do usuário principal.

Para habilitar o reconhecimento de DPI de subprocessos, chame SetThreadDpiAwarenessContext antes e após qualquer chamada de criação de janelas. A janela criada será associada ao reconhecimento de DPI que você definiu por meio do SetThreadDpiAwarenessContext. Use a segunda chamada para restaurar o reconhecimento de DPI do thread atual.

Embora o uso do ajuste de DPI de subprocessos permita que você conte com o Windows para fazer parte do ajuste de DPI do seu aplicativo, isso pode aumentar a complexidade do aplicativo. É importante que você entenda as desvantagens dessa abordagem e a natureza das complexidades que ela apresenta. Para obter mais informações sobre o reconhecimento de DPI de subprocessos, confira Ajuste de DPI de modo misto e APIs com reconhecimento de DPI.

Testando Suas Alterações

Depois de atualizar o aplicativo para torná-lo com reconhecimento de DPI por monitor, é importante validar se o aplicativo responde adequadamente às alterações de DPI em um ambiente de DPI misto. Algumas especificidades a serem testadas incluem:

  1. Movendo janelas de aplicativos entre telas com diferentes valores de DPI
  2. Iniciando seu aplicativo em telas com diferentes valores de DPI
  3. Alterar o fator de escala do seu monitor enquanto o aplicativo está sendo executado
  4. Alterando a tela que você usa como tela principal, sair do Windows e, em seguida, testar novamente o aplicativo após entrar novamente. Isso é particularmente útil para encontrar códigos que usam tamanhos/dimensões embutidos em código.

Armadilhas Comuns (Win32)

Não estão usando o retângulo sugerido fornecido em WM_DPICHANGED

Quando o Windows envia à janela do aplicativo uma mensagem WM_DPICHANGED, essa mensagem inclui um retângulo sugerido que você deve usar para redimensionar a janela. É crítico que seu aplicativo use esse retângulo para se redimensionar, pois isso o irá:

  1. Garantir que o cursor do mouse permanecerá na mesma posição relativa na Janela ao arrastar entre as telas
  2. Evitar que a janela do aplicativo entre em um ciclo recursivo de alteração de DPI, em que uma alteração de DPI dispara uma alteração de DPI subsequente, que dispara outra alteração de DPI.

Se você tiver requisitos específicos do aplicativo que o impeçam de usar o retângulo sugerido que o Windows fornece na mensagem WM_DPICHANGED, confira WM_GETDPISCALEDSIZE. Essa mensagem pode ser usada para fornecer ao Windows o tamanho desejado que você quer que seja usado uma vez que a alteração de DPI tenha ocorrido, evitando ainda os problemas descritos acima.

Falta de documentação sobre virtualização

Quando um HWND ou um processo está sendo executado sem reconhecimento de DPI ou com reconhecimento de DPI do sistema, ele pode ser ampliado por bitmap pelo Windows. Quando isso acontece, o Windows escala e converte as informações confidenciais de DPI de algumas APIs para o espaço de coordenadas da thread chamada. Por exemplo, se um thread sem conhecimento de DPI consultar o tamanho da tela durante a execução em uma tela de alto DPI, o Windows virtualizará a resposta fornecida ao aplicativo como se a tela estivesse em 96 unidades de DPI. Alternativamente, quando um thread com reconhecimento de DPI do sistema estiver interagindo com uma tela em um DPI diferente do que estava em uso quando a sessão do usuário atual foi iniciada, o Windows ajustará a escala em DPI de algumas chamadas à API no espaço de coordenadas que o HWND estaria usando se estivesse sendo executado em seu fator de escala de DPI original.

Quando você atualiza seu aplicativo da área de trabalho do Windows para escalar a DPI adequadamente, pode ser difícil saber quais chamadas à API podem retornar valores virtualizados com base no contexto do thread; atualmente, essas informações não estão suficientemente documentadas pela Microsoft. Esteja ciente de que, se você chamar qualquer API do sistema a partir de um contexto de thread sem reconhecimento de DPI ou com reconhecimento de DPI do sistema, o valor de retorno poderá ser virtualizado. Sendo assim, verifique se sua thread está sendo executada no contexto de DPI esperado ao interagir com a tela ou com janelas individuais. Ao alterar temporariamente o contexto de DPI de um thread usando SetThreadDpiAwarenessContext, certifique-se de restaurar o contexto antigo quando terminar, para evitar causar um comportamento incorreto em outras partes do aplicativo.

Muitas APIs do Windows não têm um contexto de DPI

Muitas APIs herdadas do Windows não incluem um contexto de DPI ou HWND como parte da sua interface. Como resultado, os desenvolvedores geralmente precisam fazer um trabalho adicional para lidar com a colocação em escala de qualquer informação confidencial de DPI, como tamanhos, pontos ou ícones. Por exemplo, os desenvolvedores que utilizam LoadIcon devem ampliar o bitmap dos ícones carregados ou usar APIs alternativamente para carregar os ícones corretamente dimensionados para o DPI apropriado, como LoadImage.

Reinicialização forçada do reconhecimento de DPI em todo o processo

Em geral, o modo de reconhecimento de DPI do seu processo não pode ser alterado após a inicialização do processo. Entretanto, o Windows pode alterar à força o modo de reconhecimento de DPI do seu processo se você tentar interromper o requisito de que todos os HWNDs em uma árvore de janelas tenham o mesmo modo de reconhecimento de DPI. Em todas as versões do Windows, a partir do Windows 10 1703, não é possível ter diferentes HWNDs em uma árvore HWND executados em diferentes modos de reconhecimento de DPI. Se você tentar criar um relacionamento entre elemento filho e pai que interrompa essa regra, o reconhecimento de DPI de todo o processo poderá ser redefinido. Isso pode ser disparado por:

  1. Uma chamada CreateWindow em que a janela pai passada é de um modo de reconhecimento de DPI diferente do thread que está chamando.
  2. Uma chamada SetParent em que as duas janelas estão associadas a diferentes modos de reconhecimento de DPI.

A tabela abaixo mostra o que acontece se você tentar violar essa regra:

Operação Windows 8.1 Windows 10 (1607 e anterior) Windows 10 (1703 e posterior)
CreateWindow (In-Proc) N/D Herança do Filho (modo misto) Herança do Filho (modo misto)
CreateWindow (Cross-Proc) Reinicialização forçada (do processo do chamador) Herança do Filho (modo misto) Reinicialização forçada (do processo do chamador)
SetParent (In-Proc) N/D Reinicialização forçada (do processo atual) Falha (ERROR_INVALID_STATE)
SetParent (Cross-Proc) Reinicialização forçada (do processo da janela filho) Reinicialização forçada (do processo da janela filho) Reinicialização forçada (do processo da janela filho)

Referência da API de DPI alto

Ajuste de DPI de Modo Misto e APIs com reconhecimento de DPI.