none
GetDpiForMonitor et GetScaleFactorForMonitor avec WPF RRS feed

  • Question

  • Bonjour,

    Dans une application WPF en VB, j'ouvre une fenêtre à la taille et à l'emplacement de la sélection d'une zone sur le bureau à l' aide des coordonnées de la souris.

    Cela fonctionne très bien pour des mise à l'échelle de 100%.

    Lorsque je passe sur un écran avec une autre mise à l'échelle, la fenêtre s'agrandit et se déplace par rapport aux coordonnées de la souris. Je veux donc corriger les coordonnées et tailles de ma fenêtre pour correspondre au coordonnées de ma souris pour des échelles supérieures à 100%.

    Pour réaliser cette correction, j'ai besoin de récupérer ce pourcentage d'échelle en fonction de l'écran sur lequel se trouve la sélection de la souris.

    Pour ce faire, j'utilise l'api 'MonitorFromPoint' pour récupérer le handle de l'écran correspondant aux coordonnées souris.

    Ensuite, j'ai utilisé l'api GetDpiForMonitor qui me renvoie les dpiX et dpiY de l'écran qui possède le handle.

    J'ai alors remarqué les choses suivantes en fonction du paramètre dpiType et des modifications de l'échelle de mon 2ème écran (1600x900) :

    Echelle 100% - MDT_EFFECTIVE_DPI - dpiX =96 - dpiY =96

    Echelle 100% - MDT_ANGULAR_DPI - dpiX =89 - dpiY =89

    Echelle 100% - MDT_RAW_DPI - dpiX =90 - dpiY =90

    Echelle 125% - MDT_EFFECTIVE_DPI - dpiX =96 - dpiY =96

    Echelle 125% - MDT_ANGULAR_DPI - dpiX =72 - dpiY =72

    Echelle 125% - MDT_RAW_DPI - dpiX =73 - dpiY =73

    Echelle 150% - MDT_EFFECTIVE_DPI - dpiX =96 - dpiY =96

    Echelle 150% - MDT_ANGULAR_DPI - dpiX =60 - dpiY =60

    Echelle 150% - MDT_RAW_DPI - dpiX =61 - dpiY =61

    Pourquoi avec MDT_EFFECTIVE_DPI, il n'y a pas de changement des dpi?

    J'ai ensuite essayer d'utiliser l'api 'GetScaleFactorForMonitor'.

    J'ai alors remarqué les choses suivantes :

    Echelle 100% - pscale = 100

    Echelle 125% - pscale = 100

    Echelle 150% - pscale = 140

    Pourquoi les valeurs de retour avec les échelles de 125% et 150% ne sont-elles pas correctes?

    Merci pour vos réponses éventuelles

    Jacky





    vendredi 29 mai 2020 16:51

Réponses

  • Bonjour,

    Suite aux problèmes exposés, j'ai créé un programme pour WinForm et un pour WPF avec l'utilisation des api nécessaires et la fonction  'MouseHookProc'.

    Voici en mes résultats :

    Conclusions:

    Dans tous les cas, le retour des coordonnées souris de ma fonction 'MouseHookProc' ne tient pas compte de la mise à l'échelle des écrans.

    Pour WPF, si on veut récupérer l'échelle correcte de chaque moniteur par l'api 'GetDpiForMonitor', il faut ajouter un fichier de manisfeste au projet et ajouter les balises comme décrit sur ce lien Per Monitor DPI.

    On pourra alors adapter les coordonnées souris avec l'échelle récupérée.

    Une question reste toujours posée, pourquoi les coordonnées de la souris renvoyées par ma fonction 'MouseHookPoc' ne sont-elles pas adaptées à l'échelle?

    Ce problème était-il présent sur d'ancienne version de Windows?

    Ces coordonnées seront-elles modifiées à l'avenir?

    Merci à Castorix31 pour son aide.


    dimanche 31 mai 2020 10:26

Toutes les réponses

  • Pour les APIs comme GetDpiForMonitor, il faut que l'appli soit "DPI Aware"

    Pourtant il y a indiqué : 

    "Windows Presentation Foundation (WPF) applications are automatically DPI-aware and do not need to opt in"

    Je n'ai pas testé en WPF, mais en Winforms, il faut ajouter un Manifest avec : 

      <application xmlns="urn:schemas-microsoft-com:asm.v3">
        <windowsSettings>
          <dpiAware xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">true/PM</dpiAware>
          <dpiAwareness xmlns="http://schemas.microsoft.com/SMI/2016/WindowsSettings">PerMonitor</dpiAwareness>
         </windowsSettings>
      </application>
    pour que les valeurs retournées soient correctes.

    vendredi 29 mai 2020 18:02
  • Bonjour,

    En WPF, la fenêtre s'adapte correctement à l'échelle de l'écran.

    Mon problème vient du fait que je récupère les coordonnées de la souris dans la structure MSLLHOOKSTRUCT venant de la gestion d'une fonction 'MouseHookProc'.

    Apparemment, ces coordonnées ne tiennent pas compte de la mise à l'échelle de l'écran.

    Donc mon but est de récupérer la valeur de la mise à l'échelle et de fournir aux propriétés top, left, width et height au moment de la création de ma fenêtre, les valeurs adaptées à cette échelle.

    Exemple: coordonnée souris = 150 - échelle  = 150% - valeur propriété fenêtre calculée = 100

    De cette façon,  ma fenêtre s'adaptera au dimension du rectangle de sélection du bureau.

    Pour mes essais, j'ai 2 écrans avec le mode étendu.Ces 2 écrans ont des résolutions différentes.

    A l'aide de l'api 'GetDpiForMonitor' avec le paramètre dpiType sur MDT_EFFECTIVE_DPI, j'ai remarqué que si je change le facteur d'échelle du moniteur principal, je retrouve bien le bon facteur d'échelle mais sur les moniteurs.

    Comment retrouver le facteur d'échelle correct des moniteurs secondaires en mode étendu?

    Jacky.


    samedi 30 mai 2020 04:59
  • Mais le Manifest ne change rien ?

    Car avec GetDpiForMonitor, sans Manifest, j'obtiens toujours 96 avec  MDT_EFFECTIVE_DPI,

    mais j'obtiens les bonnes valeurs avec un Manifest :

    100% : 96
    125% : 120
    150% : 144
    175% : 168

    samedi 30 mai 2020 06:01
  • Bonjour,

    Je pense qu'il n'y a pas besoin de créer un manifest pour l'adaptation de la taille des fenêtre à l'écran en WPF.

    Si je déplace une fenêtre créée en WPF entre mes 2 moniteurs avec des échelles différentes, celle-ci s'adapte très bien aux différentes échelles des moniteurs.

    J'ai lu sur des forums que microsoft avait changé sa manière d'adaptation des fenêtres à l'écran en fonction des échelles par rapport aux anciennes versions de windows.

    N'y a-t-il pas un problème avec cette nouvelle gestion pour plusieurs moniteurs de résolution différente en mode étendu?

    Pourquoi les coordonnées de la souris renvoyées par ma fonction 'MouseHookPoc' ne sont-elles pas adaptées à l'échelle? Ce problème était-il présent sur d'ancienne version de Windows?

    Avec MDT_EFFECTIVE_DPI, la fonction 'GetDipForMonitor' fonctionne très bien pour l'écran principal, mais pas pour l'écran secondaire en mode étendu. L'écran secondaire garde les dpi de l'écran principal. 

     

    samedi 30 mai 2020 07:22
  • Je pense qu'il n'y a pas besoin de créer un manifest pour l'adaptation de la taille des fenêtre à l'écran en WPF.

    //...

    Avec MDT_EFFECTIVE_DPI, la fonction 'GetDipForMonitor' fonctionne très bien pour l'écran principal, mais pas pour l'écran secondaire en mode étendu. L'écran secondaire garde les dpi de l'écran principal. 


    Non, mais le Manifest est nécessaire en Winforms (ou SetProcessDpiAwareness en C++)

    avec dpiAwareness = PerMonitor

    pour que les APIs fonctionnent correctement.

    C'est entre autres expliqué avec l'exemple du Notepad à High DPI Scaling Improvements...

    (Making Notepad Per-Monitor DPI Aware)



    samedi 30 mai 2020 08:02
  • Bonjour,

    Merci pour vos réponses.

    J'ai suivi vos suggestions et ajouté un manifest dans mon projet WPF.

    Dans ce fichier, j'ai trouvé les balises suivantes concernant l'activation du dpi par moniteur :

    <!-- Indique que l'application prend en charge DPI et qu'elle n'est pas automatiquement mise à l'échelle par Windows à un niveau de
           DPI plus élevé. Les applications Windows Presentation Foundation (WPF) prennent automatiquement en charge DPI et n'ont pas besoin 
           d'opter pour ce choix. Les applications Windows Forms qui ciblent .NET Framework 4.6 et qui optent pour ce paramètre, doivent 
           également affecter la valeur 'true' au paramètre 'EnableWindowsFormsHighDpiAutoResizing' dans leur fichier app.config. -->
      <!--
      <application xmlns="urn:schemas-microsoft-com:asm.v3">
        <windowsSettings>
          <dpiAware xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">true</dpiAware>
        </windowsSettings>
      </application>
      -->

    Malgré l'indication du message signifiant que les applications Windows Presentation Foundation (WPF) prennent automatiquement en charge DPI, J'ai activé les balises et ajouté la balise 'dpiAwareness' comme ci dessous 

    <application xmlns="urn:schemas-microsoft-com:asm.v3">
        <windowsSettings>
          <dpiAwareness xmlns ="http://schemas.microsoft.com/SMI/2016/WindowsSettings"> PerMonitor </dpiAwareness>
          <dpiAware xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">true</dpiAware>
        </windowsSettings>
      </application>

    Après essai, cela n'a rien changé, je reste toujours avec les mêmes problèmes.

    Voici d'autres constatations :

    Moniteur principale - Echelle 100% - retour par api GetMonitorInfo 1680x1050

    MDT_EFFECTIVE_DPI - dpiX =96 - dpiY =96

    MDT_ANGULAR_DPI - dpiX =89 - dpiY =89

    MDT_RAW_DPI - dpiX =90 - dpiY =90

    Moniteur secondaire - Echelle 100% - retour par api GetMonitorInfo 1600x900

    MDT_EFFECTIVE_DPI - dpiX =96 - dpiY =96

    MDT_ANGULAR_DPI - dpiX =90 - dpiY =90

    MDT_RAW_DPI - dpiX =91 - dpiY =91

    Moniteur principale - Echelle 150% - retour par api GetMonitorInfo 1680x1050 (Pas normale)

    MDT_EFFECTIVE_DPI - dpiX =144 - dpiY =144

    MDT_ANGULAR_DPI - dpiX =89 - dpiY =89

    MDT_RAW_DPI - dpiX =90 - dpiY =90

    Moniteur secondaire - Echelle 100% - retour par api GetMonitorInfo 1600x900

    MDT_EFFECTIVE_DPI - dpiX =96 - dpiY =96

    MDT_ANGULAR_DPI - dpiX =90 - dpiY =90

    MDT_RAW_DPI - dpiX =91 - dpiY =91

    Moniteur principale - Echelle 100%  - retour par api GetMonitorInfo 1680x1050

    MDT_EFFECTIVE_DPI - dpiX =96 - dpiY =96

    MDT_ANGULAR_DPI - dpiX =89 - dpiY =89

    MDT_RAW_DPI - dpiX =90 - dpiY =90

    Moniteur secondaire - Echelle 150%  - retour par api GetMonitorInfo 1067x600 (Ok 150%)

    MDT_EFFECTIVE_DPI - dpiX =96 - dpiY =96 (Pas normale)

    MDT_ANGULAR_DPI - dpiX =60 - dpiY =60

    MDT_RAW_DPI - dpiX =61 - dpiY =61

    Dans tous les cas, le retour des coordonnées souris de ma fonction 'MouseHookProc' ne tient pas compte de la mise à l'échelle des écrans.



    samedi 30 mai 2020 13:01
  • Je n'ai qu'un moniteur, donc je ne peux pas faire de réels tests....

    Sinon, tu peux tester  l'exemples de MS : Per Monitor DPI

    samedi 30 mai 2020 13:41
  • Bonjour,

    Suite aux problèmes exposés, j'ai créé un programme pour WinForm et un pour WPF avec l'utilisation des api nécessaires et la fonction  'MouseHookProc'.

    Voici en mes résultats :

    Conclusions:

    Dans tous les cas, le retour des coordonnées souris de ma fonction 'MouseHookProc' ne tient pas compte de la mise à l'échelle des écrans.

    Pour WPF, si on veut récupérer l'échelle correcte de chaque moniteur par l'api 'GetDpiForMonitor', il faut ajouter un fichier de manisfeste au projet et ajouter les balises comme décrit sur ce lien Per Monitor DPI.

    On pourra alors adapter les coordonnées souris avec l'échelle récupérée.

    Une question reste toujours posée, pourquoi les coordonnées de la souris renvoyées par ma fonction 'MouseHookPoc' ne sont-elles pas adaptées à l'échelle?

    Ce problème était-il présent sur d'ancienne version de Windows?

    Ces coordonnées seront-elles modifiées à l'avenir?

    Merci à Castorix31 pour son aide.


    dimanche 31 mai 2020 10:26