2009-04-07 8 views
6

Mon application doit bloquer le mode veille/hibernation. J'ai le code en place, mais après avoir attrapé avec succès le message WM_POWERBROADCAST, ni PBT_APMQUERYSUSPEND ni PBT_APMQUERYSTANDBY sont capturés avec succès. Fait intéressant, le PBT_APMRESUMECRITICAL et PBT_APMRESUMEAUTOMATIC messages sont être pris par mon application. Question de ligne directrice: y a-t-il une raison pour laquelle mon application ne parviendrait pas à intercepter les messages de mise en attente/de suspension, mais parviendrait à attraper les messages de reprise?Impossible d'intercepter les messages de veille/suspension (winXP)

Cette Q&A [stackoverflow.com] a aidé, mais encore une fois, les messages ne semblent pas être à mon application.

Mon code (w/événement code de l'enregistrement supprimé par souci de concision):

 protected override void WndProc(ref System.Windows.Forms.Message m) 
    { 
     // Power status event triggered 
     if (m.Msg == (int)NativeMethods.WindowMessage.WM_POWERBROADCAST) 
     { 
      // Machine is trying to enter suspended state 
      if (m.WParam.ToInt32() == (int)NativeMethods.WindowMessage.PBT_APMQUERYSUSPEND || 
       m.WParam.ToInt32() == (int)NativeMethods.WindowMessage.PBT_APMQUERYSTANDBY) 
      { 
       // Have perms to deny this message? 
       if((m.LParam.ToInt32() & 0x1) != 0) 
       { 
        // If so, deny broadcast message 
        m.Result = new IntPtr((int)NativeMethods.WindowMessage.BROADCAST_QUERY_DENY); 
       } 
      } 
      return; // ?! 
     } 

     base.WndProc(ref m); 
    } 

Répondre

3

Cela fonctionne maintenant, pour XP et Vista. J'ai créé une application Winform stub avec le code correspondant (peut être nettoyé, évidemment, mais il transmet le point).

using System; 
using System.Collections.Generic; 
using System.ComponentModel; 
using System.Data; 
using System.Drawing; 
using System.Linq; 
using System.Text; 
using System.Windows.Forms; 
using System.Runtime.InteropServices; 

namespace standbyTest 
{ 
    public partial class Form1 : Form 
    { 

     [DllImport("Kernel32.DLL", CharSet = CharSet.Auto, SetLastError = true)] 
     protected static extern EXECUTION_STATE SetThreadExecutionState(EXECUTION_STATE state); 

     [Flags] 
     public enum EXECUTION_STATE : uint 
     { 
      ES_CONTINUOUS = 0x80000000, 
      ES_DISPLAY_REQUIRED = 2, 
      ES_SYSTEM_REQUIRED = 1, 
      ES_AWAYMODE_REQUIRED = 0x00000040 
     } 

     public Form1() 
     { 
      if(Environment.OSVersion.Version.Major > 5) 
      { 
       // vista and above: block suspend mode 
       SetThreadExecutionState(EXECUTION_STATE.ES_AWAYMODE_REQUIRED | EXECUTION_STATE.ES_SYSTEM_REQUIRED | EXECUTION_STATE.ES_CONTINUOUS); 
      } 

      InitializeComponent(); 

      //MessageBox.Show(string.Format("version: {0}", Environment.OSVersion.Version.Major.ToString())); 

     } 

     protected override void OnClosed(EventArgs e) 
     { 
      base.OnClosed(e); 

      if(Environment.OSVersion.Version.Major > 5) 
      { 
       // Re-allow suspend mode 
       SetThreadExecutionState(EXECUTION_STATE.ES_CONTINUOUS); 
      } 
     } 


     protected override void WndProc(ref System.Windows.Forms.Message m) 
     { 
      // Power status event triggered 
      if(m.Msg == (int)WindowMessage.WM_POWERBROADCAST) 
      { 
       // Machine is trying to enter suspended state 
       if(m.WParam.ToInt32() == (int)WindowMessage.PBT_APMQUERYSUSPEND || 
         m.WParam.ToInt32() == (int)WindowMessage.PBT_APMQUERYSTANDBY) 
       { 
        // Have perms to deny this message? 
        if((m.LParam.ToInt32() & 0x1) != 0) 
        { 
         // If so, deny broadcast message 
         m.Result = new IntPtr((int)WindowMessage.BROADCAST_QUERY_DENY); 
        } 
       } 
       return; 
      } 

      base.WndProc(ref m); 
     } 
    } 



    internal enum WindowMessage 
    { 

     /// <summary> 
     /// Notify that machine power state is changing 
     /// </summary> 
     WM_POWERBROADCAST = 0x218, 
     /// <summary> 
     /// Message indicating that machine is trying to enter suspended state 
     /// </summary> 
     PBT_APMQUERYSUSPEND = 0x0, 
     PBT_APMQUERYSTANDBY = 0x0001, 

     /// <summary> 
     /// Message to deny broadcast query 
     /// </summary> 
     BROADCAST_QUERY_DENY = 0x424D5144 


    } 
} 
+0

qu'en est-il de WPF? – Alessio

0

Êtes-vous en cours d'exécution sur Vista ou Windows Server 2008? This page dit

En raison des changements dans le modèle de gestion d'alimentation pour Windows Vista et Windows Server 2008, l'événement PBT-APMQUERYSUSPEND n'est plus livré à des applications. Au lieu de cela l'événement BT_APMSUSPEND est livré ...

Pourriez-vous l'expliquer pourquoi vous ne le voyez pas?

+0

Ceci est pour Windows XP (n'ont pas encore obtenu à Vista/2008). On dirait que ça devrait "juste fonctionner", mais ce n'est pas le cas. Je n'ai aucune idée pourquoi je capturerais les messages de "reprise" mais pas les messages de "sommeil". Des idées, quelqu'un? – Garrett

0

J'ai essayé ce même code dans une application de test sur ma (dev) machine & sur une machine (test) différente (également winXP). Sur ma machine, il continue d'échouer, ce qui signifie que la machine s'endort. Mais sur l'autre machine, ça marche! Au début, je pensais que c'était un problème de débogage par rapport au mode de sortie, mais ce n'est pas le cas.

Il semble que quelque chose soit différent à propos de ma machine de développement, même si je n'ai aucune idée de ce que cela pourrait être.

Mystère résolu ... sorta.

0

Dans Vista appelez SetThreadExecutionState pour notifier WPM que le système n'est pas inactif.

Sous Windows XP/2000:
Une application peut retourner BROADCAST_QUERY_DENY de refuser une demande ou PBT_APMQUERYSUSPEND PBT_APMQUERYSUSPENDFAILED.

MSDN: Windows XP et versions antérieures: le système diffuse un événement PBT_APMQUERYSUSPEND pour demander l'autorisation de suspendre le fonctionnement du système. Le système s'attend à ce que chaque application et chaque pilote déterminent si l'événement demandé doit se produire et renvoyer TRUE s'il se produit, ou renvoyer BROADCAST_QUERY_DENY sinon. Les demandes ne doivent pas refuser cette demande. Si une application refuse cette demande, le système diffuse un événement PBT_APMQUERYSUSPENDFAILED. Cet événement avertit les applications et les pilotes de continuer à fonctionner normalement.

Aussi, je ne pense pas que PBT_APMQUERYSTANDBY ou PBT_APMSTANDBY sont pris en charge dans Win2K. Avez-vous essayé d'enregistrer de façon glaçable la diffusion lorsque Windows s'arrête pour voir si elles sont envoyées?

+0

Merci pour les commentaires! Je n'ai pas encore écrit le code Vista, juste XP (pas inquiet pour win2k puisque ce n'est pas sur notre liste d'OS supportés). Le mystère à ce stade est pourquoi le code ne fonctionne pas sur ma machine (mais fonctionne sur la machine de test), mais je vais devoir explorer celui-ci par moi-même. =) – Garrett

+0

Content de l'avoir réparé. Dommage qu'il n'y ait pas de certification DWOMM! http://www.codinghorror.com/blog/images/works-on-my-machine-starburst.png: o – MaSuGaNa

Questions connexes