Hello World à tous !

Tu essayes de récupérer la résolution d’écran de tous tes moniteurs en C# et tu t’arraches les cheveux ? Tu es au bon endroit.

Je viens de passer l’après-midi à tenter de récupérer la résolution de tous mes écrans (internes + externes) sans que la taille du texte, apps et autre de Windows, que l’écran principal ou que la rotation d’un écran externe ne vienne me faire démouler un cake.

Le scénario

Dans le cadre d’un projet personnel, je dois développer une application WPF. Je souhaite faire en sorte qu’une même fenêtre de cette application soit ouverte sur chaque écran du PC et prenne une certaine dimension en fonction de la résolution de l’écran ciblé. Il ne me faut donc pas juste récupérer la résolution de l’écran principal (primaire) ou la résolution global (somme de tous les écrans), mais bien récupérer la résolution de tous les écrans connectés au PC.

Pour cela, rien de plus simple, il me suffit d’utiliser l’API suivante :

Oui mais ! Ceux qui ont fait cette API (et je pense que j’irais leur dire bonjour la prochaine fois que je retourne à Redmond) ont dû trouver que c’était trop facile.

Le problème

Je vais tenter d’être clair. Dans mon scénario, j’ai deux écrans :

  1. L’écran interne de mon PC (une Surface Book).
    1. Résolution : 3000 x 2000
    2. Taille du texte, apps et autre de Windows : 200%
    3. Ecran primaire : Oui
  2. Un écran externe (Asus).
    1. Résolution : 1920 x 1080
    2. Taille du texte, apps et autre de Windows : 100%

Le souci, c’est d’avoir des écrans à résolution différente, et surtout, d’avoir la taille du texte, apps et autre différent d’un écran à l’autre.

Je ne suis toujours pas sûr du pourquoi du comment, mais quand je récupère les informations sur mon écran externe via l’API ci-dessus, la résolution de celui-ci est erroné. En effet, au lieu d’avoir une largeur de 1920, l’API me dit que mon écran externe fait 3840 de large… POURQUOIIIII !!??

Et c’est ainsi que je me suis perdu et que Windows a élargie mon Anus…

En fait, la résolution de l’écran externe retournée par cette API est multipliée par deux car… la taille du texte, apps et autre de Windows sur mon écran « primaire » (ici, mon écran interne… pas mon écran externe hein…) est à 200%.

windowsscale

Oui, vous avez bien lu. Toutes les résolutions récupérées via l’API Screen.AllScreens sont multipliés par le Scale de l’écran primaire… SAUF, pour la résolution de l’écran primaire question.

« OK Etienne m’a perdu. »

T’inquiètes je reprends ! Voici mes écrans et ce que me retourne l’API :

Résolution d’écran dans Windows Scale Résolution selon l’API
Ecran primaire 3000 x 2000 200 % 3000 x 2000
Ecran secondaire 1920 x 1080 100 % 3840 x 2160 (WTF !)
Ecran secondaire (bis) 1920 x 1080 125 % 3072 x 1728 (WTF bis !)

 

Pourquoi la résolution d’écran change en fonction de la taille de rendue des éléments à l’écran ? Je ne le sais toujours pas. Tout ce que je sais, c’est que j’ai eu du mal à récupérer la vraie résolution de chaque écran.

J’ai bien essayé d’utiliser des APIs plus bas niveau pour récupérer la résolution, mais le résultat était similaire.

Du coup, Reverse Engineering. En faisant le lien entre les diverses données du tableau ci-dessus, et en faisant des tests avec plusieurs résolutions, tailles de texte, écrans primaires, positionnement et rotation des écrans, j’ai déduis la formule magique qui permet de récupérer la vraie résolution de n’importe quel écran du PC quelle que soit sa configuration :
Vraie Largeur d’un écran secondaire = Largeur selon l’API / Scale de l’écran primaire * Scale de l’écran secondaire

Exemple avec l’écran secondaire dont le Scale est à 125% :

Exemple avec l’écran secondaire dont le Scale est à 100% :

Ainsi, pour connaître la vraie résolution d’un écran secondaire, je dois connaître le Scale de l’écran primaire ainsi que celui de l’écran secondaire.

Le résultat

Après quelques recherches, j’ai trouvé la bonne API… Du moins je pense… Je vous explique.

J’ai trouvé l’API Win32 GetScaleFactorForMonitor qui doit me retourner le Scale du moniteur spécifié. A par que la documentation n’est pas à jour dans le sens ou en réalité l’API retourne un simple nombre entier et n’est pas limitée à l’énumération décrite, elle fonctionne très bien sous Windows 10 Anniversary Update. Je n’ai pas testé sous d’autres Builds mais sachez que chez certains, l’API retourne des valeurs qui ne correspondent pas au véritable Scale de l’écran. Attention donc. Si vous êtes sous une Build antérieur de Windows 10 ou sous Windows 8.1, ça peut vous jouer des tours.

J’ai également trouvé l’API GetDpiForMonitor qui peut être utile, mais j’ai fait sans.

J’ai ensuite rapidement codé l’algorithme suivant qui permet de récupérer les véritables résolutions de chaque écran de votre PC, quelle que soit la taille du texte sur chacun de ces écrans.

N’hésitez pas à me faire des feedbacks. Si vous avez trouvé plus simple ou si savez pourquoi l’API de base se comporte ainsi, je suis preneur.

A bientôt ! 😀