Processus inopinément conscient de DPI

Sep 12 2020

J'ai un service qui lance un exécutable dans une session utilisateur avec CreateProcessAsUser, en spécifiant le bureau dans le STARTUPINFOparamètre. Ça marche bien.

Mon exécutable ne se manifeste pas et n'appelle aucune API liée à DPI.

Lorsque je lance manuellement mon exécutable en double-cliquant ou via cmd.exe, le Gestionnaire des tâches affiche correctement la prise de conscience DPI comme "Inconnu".

Cependant, lorsque mon exécutable est lancé par le service, le Gestionnaire des tâches affiche la sensibilisation DPI comme "Par moniteur" - et en effet, il se comporte comme tel.

La définition de la sensibilité DPI par défaut pour un processus indique:

Il existe deux méthodes principales pour spécifier la détection PPP par défaut d'un processus:

  1. via un paramètre de manifeste d'application
  2. par programmation via un appel API

Je ne fais aucune de ces choses.

J'ai confirmé que le .exe ne se manifestait pas en utilisant mt.exe. J'ai défini des points d'arrêt de fonction sur les éléments suivants:

  • user32.dll! SetProcessDpiAwarenessContext
  • user32.dll! SetThreadDpiAwarenessContext
  • shcore.dll! SetProcessDpiAwareness

Aucun point d'arrêt n'est atteint; cependant, une fois lancé à partir du service, je ne peux attacher mon débogueur qu'une fois que je suis déjà à l'intérieur main- et il semble que la prise de conscience DPI est déjà définie à ce stade.

Y a-t-il un autre endroit où la prise de conscience DPI peut être définie?

Il s'agit d'une application hybride rust / C - il n'y a pas (par exemple) de dépendance .NET référencée.


ÉDITER:

En utilisant le débogueur JIT, je peux interrompre mainCRTStartupet voir que DPI Awareness est déjà "PerMonitor" à ce stade. Appel SetProcessDpiAwarenessContext(DPI_AWARENESS_CONTEXT_UNAWARE)ou SetProcessDpiAwareness(PROCESS_DPI_UNAWARE)sans effet.


ÉDITER:

Lors du lancement de mon service avec CreateProcessAsUser; l'exécutable a cette variable d'environnement:

__COMPAT_LAYER = HighDpiAware

L'environnement passé à CreateProcessAsUserest créé en appelant:

CreateEnvironmentBlockavec mon pseudo utilisateur. Le reste de l'environnement est comme prévu. D'où cela vient-il? Il n'y a pas d'options de compatibilité définies sur l'exécutable lorsque j'inspecte ses propriétés dans l'explorateur ...

Réponses

2 TheNextman Sep 13 2020 at 09:55

Mon service fonctionne en tant que SYSTEM. Lorsque j'appelle CreateProcessAsUser, dans ce cas, l'exécutable est également exécuté en tant que SYSTEM. Je passe nullptrpour le lpEnvironmentparamètre. MSDN dit ceci:

Un pointeur vers un bloc d'environnement pour le nouveau processus. Si ce paramètre est NULL, le nouveau processus utilise l'environnement du processus appelant.

Cependant, lorsque j'inspecte l'environnement de mon exécutable, je vois:

__COMPAT_LAYER = HighDpiAware

Cela force la prise de conscience DPI par moniteur. Ceci est mystérieux car, en effet, AppCompatFlag est défini pour cet exécutable dans le registre pour S-1-5-18 (SYSTEM), mais je ne sais pas comment ni d'où vient cette valeur.

La variable n'est pas définie sur mon service (qui s'exécute également en tant que SYSTEM) - les services n'obtiennent probablement pas l'environnement AppCompat? Mais pourquoi mon processus enfant l'a-t-il, alors qu'il hérite supposément de l'environnement de son parent? Je suppose que ces indicateurs de compatibilité doivent avoir un traitement spécial.

Quoi qu'il en soit, la réponse à ma question est: supprimer HighDpiAwarede la __COMPAT_LAYERvariable d'environnement.