Comment détecter la veille prolongée du système depuis un service Windows

Les événements de mise en veille prolongée (Sleep / Hibernate) peuvent s’avérer indispensables pour une application connectée, car les connexions vont être interrompues. Cet article présente deux approches: la première basée sur l’API standard SystemEvents, qui pose problème dans un service Windows; l’autre basée sur WMI qui fonctionnera dans tous les cas de figure (pour autant que je sache).

SystemEvents.PowerModeChanged

Le framework .NET fournit l’API SystemEvents à cet effet, avec l’événement PowerModeChanged.

Malheureusement, comme l’indique MSDN, cette API ne fonctionne pas en mode Service sans un petit « hack ».

MSDN recommande deux alternatives pour utiliser SystemEvents depuis un service Windows:

  • Instancier une fenêtre (Form) masquée.
  • Configurer le service pour interagir avec le bureau (ce qui n’est possible qu’avec le compte de service Local System, à moins d’avoir lu cet article).

Concrètement, SystemEvents dépend du mécanisme Message Pump mis en oeuvre automatiquement sur le thread principal lorsqu’on instancie la première fenêtre de l’application.

Aucune de ces deux solutions n’est vraiment élégante et il existe un autre moyen basé sur WMI, qui ne requiert aucun de ces hacks.

WMI

WMI, ou faut-il dire CIM maintenant, propose à cet effet l’API Win32_PowerManagementEvent.

Un exemple complet en C# est ici.

La logique est dans le composant Win32PowerManagementEventWatcher. La seule subtilité est que l’on traite indifféremment les événements ResumeFromSuspend et ResumeAutomatic comme une sortie de veille. À ce sujet, je vous conseille de lire les détails sur Stackoverflow.

Conclusions

En conclusion, sur une application avec une interface utilisateur (WinForms, WPF, ou console), l’API standard SystemEvents devrait être le premier choix car c’est le plus simple et le plus performant dans cette situation.

Cependant, contrairement à ce qui est proposé par MSDN, sur une application sans interface, je pense que WMI est la méthode la plus propre. Certes WMI est réputé pour être lent, cependant cette API consiste ici à s’abonner à un événement: l’inscription peut être lente mais celle-ci est typiquement effectuée une seule fois pour toute la durée de vie de l’application. Les notifications elles-mêmes ne paraissent pas être significativement plus lentes.