Les applications qui cassent à la reprise de veille — comment fonctionnent les événements d'alimentation Windows et comment construire des applications métier qui y survivent

· · Windows, Gestion de l'alimentation, Développement Windows, Applications métier, Contrôle de périphériques, Investigation de bugs, Win32 API

« J’ai fermé le portable, je l’ai ouvert le lendemain matin, et l’application métier était pleine d’erreurs. » « L’application de surveillance d’équipement perd des données uniquement après le déjeuner. » « L’outil résident qui exporte vers Excel s’arrête parfois sur une erreur de connexion. » — Ces tickets partagent un seul suspect. La veille.

Les applications métier de l’époque où les PC de bureau étaient le courant dominant ont été écrites sur l’hypothèse tacite que « le PC reste allumé ». Le champ de bataille principal aujourd’hui est le portable, et par défaut il se met en veille après quelques minutes d’inactivité. Sur une machine compatible Modern Standby, la sémantique même de la veille a changé par rapport au modèle traditionnel. Destiné aux développeurs qui écrivent des applications métier et des logiciels de contrôle d’équipement sous Windows, cet article organise, à partir des sources primaires, ce que l’OS notifie à une application avant et après la veille, ce qui casse, et comment écrire une application qui survit à la reprise.

1. La conclusion, d’abord

  • La veille est un événement que l’application n’a « pas le droit de refuser ». Vous êtes notifié juste avant avec WM_POWERBROADCAST (PBT_APMSUSPEND), mais le délai de grâce est d’environ 2 secondes, et lors d’une suspension d’urgence la notification n’arrive même pas.12
  • À la reprise depuis la suspension, PBT_APMRESUMEAUTOMATIC arrive, et lors d’une reprise initiée par l’utilisateur PBT_APMRESUMESUSPEND arrive aussi. Le travail requis tel que la reconnexion appartient en règle générale au premier. Les transitions d’entrée et de sortie de l’inactivité basse consommation de Modern Standby ne s’alignent toutefois pas toujours sur ces notifications, donc traitez les notifications comme une aide.34
  • Concevez en partant du principe que les connexions TCP, les ports série et les handles de périphérique ne survivent pas à travers la reprise. Une logique de reconnexion qui les reconstruit à une notification de reprise ou à une erreur de communication est l’événement principal.
  • Surveillez les minuteries et le traitement du temps. Le travail périodique s’arrête pendant la veille, et la façon dont il se déclenche immédiatement après la reprise diffère selon l’API de minuterie et le runtime. Un « énorme saut du temps écoulé » se produit aussi, donc l’approche sûre est de reconstruire le planning à la reprise.
  • Supprimez la veille explicitement pour les intervalles que vous ne voulez pas interrompre. Utilisez SetThreadExecutionState (ES_SYSTEM_REQUIRED) ou une demande d’alimentation (PowerSetRequest), et levez-la toujours lorsque le travail se termine.45
  • Sur une machine Modern Standby le système tourne encore par intermittence pendant la veille, mais les applications de bureau sont mises en pause. Vous ne pouvez pas tenir l’attente que « notre application devrait continuer de tourner pendant la veille ».6
  • Les outils d’investigation standard sont powercfg (/requests, /lastwake, /sleepstudy) et Kernel-Power dans le journal d’événements.

2. Ce qui se passe autour de la veille — le flux des événements d’alimentation

L’OS diffuse les changements d’état d’alimentation à chaque application sous la forme d’un message WM_POWERBROADCAST.2 Il y a trois événements principaux qui impliquent la veille et la reprise.

Événement Signification
PBT_APMSUSPEND Sur le point d’entrer en veille (la dernière chance de se préparer)
PBT_APMRESUMEAUTOMATIC A repris (arrive toujours à la reprise)
PBT_APMRESUMESUSPEND Reprise causée par une action de l’utilisateur (celui-ci est conditionnel)

PBT_APMSUSPEND est la notification juste avant la veille, et ici vous pouvez vous préparer en fermant des fichiers et en enregistrant l’état. Il y a toutefois deux conditions. Première, le temps accordé au traitement est d’environ 2 secondes par application, et si vous le dépassez le système poursuit sans attendre.1 Deuxième, lors d’une suspension d’urgence telle qu’une batterie critiquement faible, il se met en veille immédiatement sans notification préalable.2 Une conception qui « doit terminer avant la veille » ne tient pas. Traitez la notification comme une chance de « le faire si vous y arrivez », et placez le travail principal du côté de la reprise.

Le côté reprise se fait en deux étapes. PBT_APMRESUMEAUTOMATIC arrive à la reprise depuis une transition de suspension. En plus de cela, si la machine a repris à cause d’une action de l’utilisateur telle que le bouton d’alimentation ou une touche (ou si la présence de l’utilisateur a été détectée ensuite), PBT_APMRESUMESUSPEND suit. Inversement, une reprise sans surveillance pour un réveil distant sur le réseau ou pour de la maintenance ne délivre que PBT_APMRESUMEAUTOMATIC.3 Ces deux étapes sont elles-mêmes un indice pour scinder le travail — faites la récupération mécanique telle que reconstruire les connexions sur PBT_APMRESUMEAUTOMATIC, et faites les actions visibles par l’utilisateur telles que les mises à jour d’écran ou une invite de reconnexion sur PBT_APMRESUMESUSPEND.

Flux de notification pour la veille et la reprisePBT_APMSUSPEND arrive juste avant la veille avec environ 2 secondes de grâce ; à la reprise, PBT_APMRESUMEAUTOMATIC arrive toujours, et PBT_APMRESUMESUSPEND ne suit que pour une reprise initiée par l'utilisateurApplicationOSApplicationOSVeille (le code ne s'exécute pas)PBT_APMSUSPEND (environ 2 secondes de grâce)Enregistrer l'état et fermer les connexionsPBT_APMRESUMEAUTOMATIC (arrive à la reprise)Reconnecter et restaurer l'étatPBT_APMRESUMESUSPEND (reprise initiée par l'utilisateur seulement)Mises à jour d'écran et autre travail visible

Figure 1 : les notifications ne sont que « un mot juste avant, et un ou deux mots après la reprise ». La vedette de la récupération est le travail du côté de la reprise.

Différence entre la veille ordinaire et la suspension d'urgenceLa veille ordinaire délivre PBT_APMSUSPEND juste avant avec environ 2 secondes pour se préparer, mais une suspension d'urgence telle qu'une batterie critique s'arrête sans notification préalable, donc une conception qui dépend de la notification préalable ne tient pasVeille ordinairePBT_APMSUSPEND (environ 2 s de grâce)Se préparer, puis s'arrêterSuspension d'urgence (batterie critique)S'arrêter sans notification préalableUne conception qui suppose la notification ne tient pas

Figure 2 : une suspension d’urgence arrive sans avertissement. Donc la préparation est « un bonus si vous y arrivez », et le travail principal va du côté de la reprise.

Notez que WM_POWERBROADCAST ne distingue pas le type d’état basse consommation (veille versus mise en veille prolongée).4 La bonne abstraction pour l’application est de le traiter comme un seul type d’événement : « ça s’est arrêté, et ça est revenu ». Les services sans fenêtre et les applications console peuvent recevoir les mêmes notifications en utilisant RegisterSuspendResumeNotification sous forme de callback (DEVICE_NOTIFY_CALLBACK).7

Scission du travail entre les deux étapes de reprisePlacez la récupération mécanique telle que la reconnexion sur PBT_APMRESUMEAUTOMATIC, qui arrive à la reprise ; placez le travail visible par l'utilisateur tel que les mises à jour d'écran ou une invite de reconnexion sur PBT_APMRESUMESUSPEND, qui n'arrive que lors d'une reprise initiée par l'utilisateurPBT_APMRESUMEAUTOMATIC (à la reprise)Récupération mécaniquePBT_APMRESUMESUSPEND (reprise utilisateur)Travail visible par l'utilisateurReconnecter et rouvrir les handlesMises à jour d'écran et invite de reconnexion

Figure 3 : le second n’arrive pas lors d’une reprise sans surveillance, donc placer la récupération requise sur le second la manquera.

3. Modern Standby — le sens de « veille » a changé

Un autre fait moderne à intégrer est Modern Standby. La veille S3 traditionnelle était un modèle simple qui « arrêtait le système dans son ensemble » ; la veille sur une machine Modern Standby est un modèle de type smartphone dans lequel le système continue de tourner par intermittence après que l’écran s’éteint.

Ce qui compte pour une application métier ici, c’est que les applications de bureau sont mises en pause par le Desktop Activity Moderator (DAM) dès la première étape d’entrée en veille.6 Le système lui-même tourne encore de temps en temps pour maintenir le réseau et recevoir des notifications, mais les composants qui en bénéficient sont ceux qui participent à ce mécanisme — le code ordinaire d’une application de bureau ne s’exécute pas. Donc du point de vue d’un développeur, la conclusion est la même pour Modern Standby et pour S3 — concevez en partant du principe que votre code ne s’exécute pas pendant la veille.

Différence entre la veille traditionnelle et Modern StandbyLa veille S3 traditionnelle arrête le système dans son ensemble, tandis que sous Modern Standby le système tourne encore par intermittence après que l'écran s'éteint. Les applications de bureau sont mises en pause par le DAM dans les deux cas, donc le code de l'application ne s'exécute pasVeille S3 traditionnelle : tout le système s'arrêteLe code de l'application ne s'exécute pasModern Standby : le système tourne par intermittenceLes applications de bureau sont mises en pause par le DAM

Figure 4 : le modèle a changé, mais pour une application de bureau la conclusion est la même : « vous ne pouvez pas tourner pendant la veille ».

Une autre prudence est le peu de fiabilité des notifications. Sous Modern Standby, les transitions d’entrée et de sortie de l’inactivité basse consommation ne s’alignent pas sur la transition de suspension traditionnelle, et une connexion peut déjà être rompue sans qu’aucune notification n’arrive jamais. Traitez la notification de reprise comme une aide, et placez la reconnexion déclenchée par la détection d’erreur (chapitre 5) sur le chemin principal de récupération.

Une autre différence est le sentiment « glissant » du comportement. Atteindre les profondeurs de la veille se fait par étapes, et le moment des déconnexions et des arrêts n’est pas aussi net que sous S3. La distinction entre « l’écran vient juste de s’éteindre » et « il s’est mis en veille » est aussi difficile à voir pour l’utilisateur, donc lorsque vous prenez un symptôme il faut confirmer « ont-ils fermé le capot » et « combien de minutes a-t-il été laissé inactif ».

4. Ce qui casse — symptômes classiques

La connexion TCP est morte. Pendant la veille, l’autre côté, le NAT et les pare-feu traitent votre silence comme un délai d’expiration et abandonnent la connexion. Pire, le socket de ce côté ne sait pas l’erreur, donc elle n’échoue que lorsque vous envoyez ou recevez après la reprise. Ou pire encore, une attente de réception n’erre jamais du tout (c’est pourquoi il faut un keepalive). Les connexions de base de données et les WebSockets ont la même forme.

Les handles de port série et de périphérique USB deviennent invalides. Un périphérique connecté en USB peut, à la reprise, sembler avoir été « débranché puis rebranché » une fois, et le handle que vous aviez ouvert commence à renvoyer des erreurs. C’est le schéma typique d’une application de contrôle d’équipement qui « n’obtient une erreur de communication qu’après le déjeuner ». La conception de reconnexion est aussi couverte dans l’article sur la communication série.

La continuité du temps se rompt. Le travail piloté par minuterie tel que « interroger toutes les 10 secondes » ne se déclenche pas pendant la veille. La façon dont il se déclenche immédiatement après la reprise (le travail échu se déclenche une fois immédiatement, rien ne se passe jusqu’à la période suivante, etc.) diffère selon l’API de minuterie et le runtime que vous utilisez, donc ne laissez pas le traitement des ticks manqués à un comportement implicite — l’approche sûre est de reconstruire le planning à la notification de reprise. Aussi, les calculs de temps écoulé (la différence par rapport à l’horodatage précédent) deviennent soudain « l’équivalent de 8 heures », et les calculs de moyenne ou les jugements de délai d’expiration cassent. Un travail planifié tel que « s’exécuter chaque nuit à 2 h » ne s’exécute simplement pas si le PC est en veille à ce moment (réveillez-le avec la fonction de réveil depuis la veille du Planificateur de tâches si vous en avez besoin).

Trois formes dans lesquelles la continuité du temps se romptLe travail périodique s'arrête pendant la veille et le déclenchement après reprise diffère selon l'API, donc reconstruisez le planning à la reprise ; la différence par rapport à l'horodatage précédent devient énorme après la reprise, donc protégez-la ; le travail planifié ne s'exécute pas si la machine est en veille, donc envisagez le réveil du Planificateur de tâchesTravail périodique : s'arrêteReconstruire le planningTemps écoulé : exploseProtéger les écarts anormauxPlanifié : n'a jamais tournéRéveil depuis la veille

Figure 5 : écrivez le traitement des minuteries et du temps en partant du principe que « le temps saute ». Chacune des trois formes a un type de contre-mesure.

Trois choses qui cassent à travers la veilleÀ travers la veille, une connexion TCP a été abandonnée par un délai d'expiration de l'autre côté, le handle d'un périphérique USB est invalidé comme une reconnexion, et le travail basé sur le temps écoulé observe un énorme saut de temps. Récupérez chacun avec reconnexion, réouverture et une garde d'écartIntervalle de veilleTCP : le pair l'a abandonnéeUSB ou temps écoulé ?USB : handle invalideTemps écoulé : un sautDétecter + reconnecterRouvrir le périphériqueProtéger les écarts anormaux

Figure 6 : ce qui casse tombe en trois familles — « connexions », « handles » et « continuité du temps » — et chacune a un type de récupération établi.

La réauthentification aux ressources partagées. Les lecteurs réseau et les VPN ont souvent besoin d’être rétablis après la reprise, et il y a une « vallée de démarrage » de quelques secondes à plusieurs dizaines de secondes juste après la reprise dans laquelle l’accès échoue. Il est plus sûr de ne pas tout réessayer à la fois immédiatement après la reprise, mais d’attendre un peu et de réessayer par étapes.

5. Construire des applications qui survivent à la reprise

Le principe tient en une chose. Partez du principe que « les connexions et les handles ne survivent pas à travers la veille », et structurez l’application de sorte que vous puissiez toujours récupérer.

Détectez la reprise et récupérez. Lorsque WM_POWERBROADCAST de la fenêtre de premier niveau reçoit PBT_APMRESUMEAUTOMATIC, abandonnez les connexions que vous détenez et reconstruisez-les. Le point est de ne pas s’appuyer sur la seule notification de reprise. Les notifications manquées et la communication qui se produit avant la notification sont toutes deux réelles, donc couplez-la toujours à un chemin qui « se reconnecte lorsqu’une erreur de communication est détectée », et traitez la notification de reprise comme un déclencheur qui ne fait que commencer cela plus tôt.

// C#: funnel both the resume notification and communication errors into the same reconnect path
protected override void WndProc(ref Message m)
{
    const int WM_POWERBROADCAST = 0x0218;
    const int PBT_APMRESUMEAUTOMATIC = 0x0012;
    if (m.Msg == WM_POWERBROADCAST && (int)m.WParam == PBT_APMRESUMEAUTOMATIC)
    {
        _connectionManager.RequestReconnect();   // idempotent reconnect request
    }
    base.WndProc(ref m);
}

Rendez le travail de reconnexion lui-même idempotent (sûr peu importe le nombre de fois qu’il est appelé), réessayez en cas d’échec avec un backoff exponentiel, et à l’état stable détectez tôt une connexion morte avec un keepalive — mettez ces trois-là ensemble comme un ensemble, et vous survivrez non seulement à la reprise depuis la veille mais aussi à une brève coupure réseau ou à un redémarrage de périphérique.

Conception de reconnexion résiliente à la repriseLa notification de reprise, une erreur de communication et un échec de keepalive convergent tous vers le même travail de reconnexion idempotent, qui réessaie avec un backoff exponentiel en cas d'échecouinonNotification de reprise (PBT_APMRESUMEAUTOMATIC)Travail de reconnexion idempotentDétection d'erreur de communicationÉchec de keepaliveRéussi ?Retour au fonctionnement normalRéessayer après backoff exponentiel

Figure 7 : concentrez la reconnexion en un seul chemin idempotent, et entrez sur la même route depuis la notification de reprise, la détection d’erreur ou le keepalive.

Revisitez le traitement du temps. Pour le travail qui utilise « le temps écoulé depuis la dernière fois », mettez une garde qui invalide l’intervalle lorsqu’elle détecte un écart anormalement grand (ne le pliez pas dans une moyenne, ne le traitez pas comme un délai d’expiration). Mesurer le temps écoulé à travers la reprise exige de garder une distinction entre une horloge qui avance pendant la veille (l’heure murale) et le temps réellement passé au travail.

Supprimez la veille explicitement pour les intervalles que vous ne voulez pas interrompre. Pendant un travail qui ne doit pas être interrompu par la veille — une migration de données, une communication continue avec un périphérique, etc. — vous pouvez garder le système éveillé avec SetThreadExecutionState(ES_CONTINUOUS | ES_SYSTEM_REQUIRED) (ajoutez ES_DISPLAY_REQUIRED si vous voulez aussi garder l’écran allumé).45 Une méthode plus propre est l’API de demande d’alimentation (PowerCreateRequest + PowerSetRequest), qui peut attacher une chaîne de motif, et powercfg /requests montrera alors « qui le bloque et pourquoi ».8 Notez que la suppression via SetThreadExecutionState est par thread, et vous la levez depuis le même thread qui l’a définie. Pour un travail qui change de thread, tel que async/await, utilisez le côté demande d’alimentation, qui est géré par un handle. Il y a des précautions. Première, ce que celles-ci suppriment est la veille automatique d’inactivité. Elles ne peuvent pas arrêter une action explicite de l’utilisateur telle que fermer le capot ou choisir Veille dans le menu Démarrer, donc vous ne pouvez pas sauter la conception de reconnexion de ce chapitre même pendant que la suppression est active. Deuxième, sur batterie sur une machine Modern Standby, ces demandes d’alimentation sont aussi coupées un certain temps après que le délai d’expiration de la veille s’écoule. Un travail qui ne peut pas être interrompu doit être garanti par l’alimentation secteur ou par l’exploitation.8 Troisième, levez-la toujours lorsque le travail se termine. Un oubli de levée devient un nouveau bug : « ce PC, pour une raison quelconque, ne se met pas en veille ».

Deux moyens de supprimer la veilleQue vous utilisiez le commode SetThreadExecutionState ou l'API de demande d'alimentation qui peut attacher une chaîne de motif et est visible pour un administrateur via powercfg, levez-la toujours lorsque le travail se termineIntervalle de travail qui ne doit pas être interrompuSetThreadExecutionStateDemande d'alimentation (PowerSetRequest)Commode — drapeaux seulementAvec un motif — visible dans powercfgLevez-la toujours à la fin du travail

Figure 8 : pour l’un ou l’autre moyen, « levez-la lorsque vous avez fini » est une condition absolue. Une demande d’alimentation qui peut rendre le motif visible est plus gentille pour l’exploitation.

Les services et les applications sans fenêtre reçoivent des notifications par callback avec RegisterSuspendResumeNotification (DEVICE_NOTIFY_CALLBACK).7 Si le fonctionnement continu est une exigence réelle, la solution de fond est de revisiter une conception qui garde le travail résident sur un PC client qui se met en veille, et de le déplacer côté serveur ou vers une machine exploitée sans veille.

6. Investigation — powercfg et le journal d’événements

L’investigation autour de l’alimentation est bien servie par les outils livrés avec l’OS.

  • Elle ne se met pas en veille : powercfg /requests liste les processus et pilotes qui ont émis une demande d’alimentation. « L’application a oublié de lever SetThreadExecutionState » apparaît ici aussi.
  • Elle se réveille toute seule : powercfg /lastwake montre la raison du réveil le plus récent, et powercfg /waketimers montre les minuteries actuellement réservées pour réveiller la machine.
  • Qualité de Modern Standby : powercfg /sleepstudy génère un rapport de consommation d’énergie et d’activité par intervalle de veille.9
  • Confirmer la chronologie : la source Kernel-Power dans le journal d’événements (Système) conserve des enregistrements d’entrée en veille et de reprise. Les apparier au journal de l’application vous laisse confirmer objectivement si « il y a eu une reprise juste avant l’erreur ».
Correspondance des symptômes d'alimentation aux commandes d'investigationPour un symptôme de non-veille, trouvez qui détient une demande d'alimentation avec powercfg /requests ; pour un symptôme de réveil spontané, trouvez la raison du réveil avec /lastwake et /waketimers ; pour une chronologie, utilisez Kernel-Power dans le journal d'événementsElle ne se met pas en veillepowercfg /requestsElle se réveille toute seulepowercfg /lastwake et /waketimersVouloir confirmer la chronologieKernel-Power dans le journal d'événementsUne suppression de veille oubliée apparaît aussi

Figure 9 : les symptômes correspondent aux commandes d’investigation en trois familles. Confirmez d’abord « vient-elle de se mettre en veille », puis scindez.

Dans le traitement des tickets, demander d’abord « le PC était-il en veille juste avant (ont-ils fermé le capot) » accélère grandement l’isolement.

7. Résumé

  • La veille ne peut pas être refusée. La notification préalable (PBT_APMSUSPEND) est au mieux effort avec environ 2 secondes de grâce, et elle ne vient pas en urgence. Placez la conception principale du côté de la reprise.
  • Les notifications de reprise sont PBT_APMRESUMEAUTOMATIC (à la reprise depuis la suspension) + PBT_APMRESUMESUSPEND (sur une action de l’utilisateur). Gardez la reconnexion pilotée par erreur sur le chemin principal pour le cas où la notification n’arrive pas.
  • Partez du principe que les connexions et les handles ne survivent pas à travers la reprise, et implémentez l’ensemble en trois pièces d’une reconnexion idempotente + backoff exponentiel + un keepalive.
  • Mettez une garde contre les « écarts anormaux » sur le travail basé sur le temps écoulé. Concevez le travail planifié en partant du principe qu’il ne s’exécute pas pendant la veille.
  • Pour les intervalles qui ne doivent pas être interrompus, supprimez la veille explicitement avec SetThreadExecutionState ou une demande d’alimentation, et levez-la toujours lorsque vous avez fini.
  • L’investigation est powercfg (/requests, /lastwake, /sleepstudy) et le journal d’événements Kernel-Power. Dans le traitement des tickets, demandez d’abord « s’est-il mis en veille juste avant ».

Du point de vue de l’application, la veille est un événement dans lequel « le temps saute sans avertissement, les connexions avec l’entourage sont coupées, puis ça revient ». Que vous ayez tissé cela dans la conception comme une part de la vie quotidienne, plutôt que comme une situation anormale, est ce qui sépare la stabilité d’une application métier à l’ère du portable.

Articles connexes

Domaines de conseil associés

KomuraSoft LLC prend en charge l’investigation des causes profondes de bugs tels que « la communication se rompt après la reprise depuis la veille » et « la connexion au périphérique tombe après le déjeuner », le rétrofit d’une logique de reconnexion et de la gestion des événements d’alimentation sur des applications existantes, et les revues de conception d’applications métier et de logiciels de contrôle d’équipement qui supposent un fonctionnement sur portable.

Références

  1. Microsoft Learn, PBT_APMSUSPEND event. Sur le fait qu’il s’agit de l’événement qui arrive juste avant que l’ordinateur n’entre dans l’état de suspension ; sur le fait que l’application est censée terminer le travail nécessaire pour enregistrer les données ; et sur le fait que le système accorde environ 2 secondes pour traiter cette notification, une application qui continue au-delà étant sujette à interruption.  2

  2. Microsoft Learn, System Power Management Events. Sur le système qui diffuse à l’avance les changements de mode de fonctionnement tels que la veille ; sur PBT_APMSUSPEND qui est notifié avant la veille d’inactivité afin que vous puissiez vous préparer en fermant des fichiers et en enregistrant des données ; sur une suspension d’urgence (batterie critique et analogues) qui ne donne aucune notification préalable ; sur le fait que le traitement de ce message est autorisé un maximum de 2 secondes par application et est coupé après le délai d’expiration ; et sur le fait que chaque application est notifiée à la reprise.  2 3

  3. Microsoft Learn, PBT_APMRESUMESUSPEND event. Sur le fait que ceci est envoyé après PBT_APMRESUMEAUTOMATIC lors d’une reprise initiée par l’utilisateur ou lorsqu’une entrée utilisateur est détectée ensuite ; sur le fait que seul PBT_APMRESUMEAUTOMATIC est envoyé pour une reprise d’une cause externe telle qu’un réveil distant ; et sur le fait que l’application est censée rouvrir les fichiers fermés au moment de la veille et se préparer à l’entrée utilisateur.  2

  4. Microsoft Learn, WM_POWERBROADCAST message. Sur le fait que PBT_APMRESUMEAUTOMATIC est toujours envoyé à la reprise, avec PBT_APMRESUMESUSPEND envoyé aussi lors d’une reprise depuis une entrée utilisateur ; sur le fait que ce message ne distingue pas le type d’état basse consommation ; sur le fait que les détails des transitions d’état d’alimentation sont enregistrés dans le journal d’événements système ; et sur l’appel à SetThreadExecutionState pour empêcher le système d’entrer dans un état basse consommation.  2 3 4

  5. Microsoft Learn, SetThreadExecutionState function (winbase.h). Sur le fait que ES_SYSTEM_REQUIRED et ES_DISPLAY_REQUIRED peuvent supprimer la veille d’inactivité du système et l’extinction de l’affichage ; et sur le fait de déclarer une suppression continue avec ES_CONTINUOUS et de la lever en appelant ES_CONTINUOUS seul lorsque vous avez fini.  2

  6. Microsoft Learn, Prepare software for modern standby. Sur le Desktop Activity Moderator (DAM) qui met en pause les applications de bureau dès la première étape de la transition vers Modern Standby ; et sur le système qui passe ensuite par étapes dans une phase basse consommation et une phase de résilience, seuls les composants autorisés tournant par intermittence.  2

  7. Microsoft Learn, RegisterSuspendResumeNotification function (winuser.h). Sur le fait qu’il s’agit de l’API qui s’enregistre pour recevoir les notifications de suspension/reprise, et sur le fait de spécifier DEVICE_NOTIFY_CALLBACK afin qu’une application sans fenêtre ou un service puisse recevoir la notification via un callback en plus de la livraison de message à un handle de fenêtre.  2

  8. Microsoft Learn, PowerSetRequest function (winbase.h). Sur le fait de pouvoir définir un type de demande tel que maintien éveillé du système ou de l’affichage sur un objet de demande d’alimentation créé avec PowerCreateRequest ; sur le fait de pouvoir attacher une chaîne de motif de diagnostic ; et sur le fait que les demandes d’alimentation en cours sont énumérables avec powercfg /requests.  2

  9. Microsoft Learn, Modern standby SleepStudy. Sur le rapport généré par powercfg /sleepstudy qui vous laisse inspecter, par intervalle Modern Standby, la consommation d’énergie, l’activité et la raison du réveil (bouton d’alimentation, entrée utilisateur, une minuterie de réveil, etc.). 

Articles récents partageant les mêmes étiquettes, pour approfondir des sujets proches.

Ces pages replacent le sujet dans un contexte plus large de services et de décisions.

Cet article est directement lié aux services suivants.

Questions fréquentes

Questions souvent posées lors d’une consultation sur le sujet de cet article.

Une application peut-elle apprendre la veille à l'avance et la refuser ?
Sous Windows actuel, vous pouvez recevoir la notification, mais vous ne pouvez pas la refuser. Juste avant la veille, un message WM_POWERBROADCAST délivre un événement PBT_APMSUSPEND, et ici vous pouvez vous préparer en fermant des fichiers et en enregistrant l'état, mais le temps accordé au traitement est d'environ 2 secondes par application, et si vous le dépassez le système poursuit sans attendre. Lors d'une suspension d'urgence telle qu'une batterie critiquement faible, la notification préalable elle-même n'arrive pas. Une conception qui « doit terminer avant la veille » ne tient donc pas ; il faut une conception capable de se rétablir à la reprise, peu importe le moment de la coupure. Pour un intervalle de travail que vous ne voulez vraiment pas interrompre par la veille, supprimez-la explicitement avec SetThreadExecutionState ou une demande d'alimentation (PowerSetRequest).
Comment détecter que la machine a repris ?
Si l'application a une fenêtre, gérez WM_POWERBROADCAST. À la reprise depuis la suspension, PBT_APMRESUMEAUTOMATIC arrive, et si la reprise a été causée par une action de l'utilisateur (le bouton d'alimentation ou une touche), PBT_APMRESUMESUSPEND le suit. Une reprise sans surveillance qui se remet en veille immédiatement ne délivre que PBT_APMRESUMEAUTOMATIC, donc la scission de base consiste à placer le travail requis tel que la reconnexion du côté PBT_APMRESUMEAUTOMATIC et le travail visible par l'utilisateur tel que les mises à jour d'écran du côté PBT_APMRESUMESUSPEND. Les services sans fenêtre et les applications console peuvent recevoir les mêmes notifications via un callback en utilisant RegisterSuspendResumeNotification avec DEVICE_NOTIFY_CALLBACK.
Puis-je garder l'application en cours d'exécution pendant la veille ?
En règle générale, non. Pendant la veille, l'exécution du CPU elle-même s'arrête (sur une machine Modern Standby, les applications de bureau sont mises en pause par le Desktop Activity Moderator), et le code de l'application ne s'exécute pas. Il y a deux choix. L'un consiste à supprimer la veille uniquement pendant que le travail est en cours. Spécifier ES_SYSTEM_REQUIRED avec SetThreadExecutionState, ou émettre une demande d'alimentation avec PowerCreateRequest/PowerSetRequest, supprime la veille automatique d'inactivité pendant cet intervalle (vous pouvez le confirmer avec powercfg /requests). Cela ne peut toujours pas arrêter une action de veille explicite telle que l'utilisateur qui ferme le capot, donc vous devez encore être prêt pour la reprise même pendant que la suppression est active. L'autre consiste à accepter la veille et à concevoir pour « rattraper après la reprise ». Pour un travail planifié tel qu'un lot nocturne, vous pouvez aussi réveiller le PC avec « Réveiller l'ordinateur pour exécuter cette tâche » du Planificateur de tâches. Un travail qui a vraiment besoin de tourner en continu appartient à un serveur ou à un service configuré pour ne pas se mettre en veille.
Pourquoi les connexions TCP et les ports série cessent-ils de fonctionner après la reprise ?
Parce que les adaptateurs réseau et les périphériques USB passent aussi dans un état basse consommation pendant la veille. La connexion TCP a déjà été abandonnée par l'autre côté ou par un délai d'expiration NAT ou de pare-feu, et l'envoi/réception après la reprise renvoie une erreur (vous ne le remarquez souvent que lorsqu'elle se produit). Les adaptateurs USB-série et analogues sont parfois traités comme un retrait puis une réinsertion de périphérique à la reprise, et le handle que vous aviez ouvert devient invalide. Dans les deux cas, la bonne hypothèse est que « les handles et les connexions ne survivent pas à travers la reprise », et la bonne réponse est d'implémenter une logique de reconnexion qui reconstruit la connexion à une notification de reprise ou à une erreur de communication. Combiner un keepalive périodique avec des nouvelles tentatives qui utilisent un backoff exponentiel en cas d'échec est le schéma établi.
Comment investiguer une veille inattendue ou une reprise inattendue ?
La commande powercfg est le premier outil. Dans le sens « elle ne se met pas en veille », powercfg /requests liste quels processus et pilotes ont émis une demande d'alimentation qui bloque la veille. Dans le sens « elle se réveille toute seule », powercfg /lastwake montre la raison du réveil le plus récent et powercfg /waketimers montre les minuteries actuellement réservées pour réveiller la machine. Sur une machine Modern Standby, powercfg /sleepstudy produit un rapport de consommation et d'activité pendant la veille. L'historique de veille et de reprise est aussi enregistré dans le journal d'événements (la source Kernel-Power dans le journal Système), donc vous pouvez confirmer sur une chronologie « quand elle s'est mise en veille, et quand et pourquoi elle s'est réveillée ».

Profil de l’auteur

Page de présentation de l’auteur de l’article.

Go Komura

Représentant de KomuraSoft LLC

Spécialisé dans le développement de logiciels Windows, le conseil technique et l’analyse de pannes, notamment pour les systèmes existants et les incidents difficiles à reproduire.

Retour au blog