2010-02-05 22 views
12

Ciao Ho cercato ma non riesco a trovare la risposta. Come faccio a sapere quando lo schermo si sta spegnendo o accendendo. Non SystemEvents.PowerModeChanged. Non so come recuperare i display/schermo EVENTIC# Come ottenere gli eventi quando lo schermo/display si spegne o si accende?

private const int WM_POWERBROADCAST  = 0x0218; 
     private const int WM_SYSCOMMAND   = 0x0112; 
     private const int SC_SCREENSAVE   = 0xF140; 
     private const int SC_CLOSE    = 0xF060; // dont know 
     private const int SC_MONITORPOWER  = 0xF170; 
     private const int SC_MAXIMIZE   = 0xF030; // dont know 
     private const int MONITORON = -1; 
     private const int MONITOROFF = 2; 
     private const int MONITORSTANBY = 1; 
[DllImport("user32.dll")] 
     //static extern IntPtr SendMessage(IntPtr hWnd, uint Msg, IntPtr wParam, IntPtr lParam); 
     private static extern int SendMessage(IntPtr hWnd, int hMsg, int wParam, int lParam); 
     public void Init(Visual visual) 
     { 
      SystemEvents.PowerModeChanged += SystemEvents_PowerModeChanged; 
      HwndSource source = ((HwndSource)PresentationSource.FromVisual(visual)); 
      source.AddHook(MessageProc); 
      Handle = source.Handle; 

     } 
public void SwitchMonitorOff() 
     { // works 
       SendMessage(Handle, WM_SYSCOMMAND, SC_MONITORPOWER, MONITOROFF); 
     } 
     public void SwitchMonitorOn() 
     {// works 
      SendMessage(Handle, WM_SYSCOMMAND, SC_MONITORPOWER, MONITORON); 
     } 
     public void SwitchMonitorStandBy() 
     {// works 
      SendMessage(Handle, WM_SYSCOMMAND, SC_MONITORPOWER, MONITORSTANBY); 
     } 

private IntPtr MessageProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled) 
     { 


      if (msg == WM_SYSCOMMAND) //Intercept System Command 
      { 
       // not finished yet 
       // notice the 0xFFF0 mask, it's because the system can use the 4 low order bits of the wParam 
       // value as stated in the MSDN library article about WM_SYSCOMMAND. 
       int intValue = wParam.ToInt32() & 0xFFF0; 
       switch (intValue) 
       { 
        case SC_MONITORPOWER: //Intercept Monitor Power Message 61808 = 0xF170 
         InvokeScreenWentOff(null); 
         Log("SC:Screen switched to off"); 
         break; 
        case SC_MAXIMIZE: // dontt know : Intercept Monitor Power Message 61458 = 0xF030, or 
         //InvokeScreenWentOn(null); 
         Log("SC:Maximazed"); 
         break; 
        case SC_SCREENSAVE: // Intercept Screen saver Power Message 61760 = 0xF140 
         InvokeScreenSaverWentOn(null); 
         Log("SC:Screensaver switched to on"); 
         break; 
        case SC_CLOSE: // I think resume Power Message 61536 = 0xF060 
         //InvokeScreenWentOn(null); 
         //InvokeScreenSaverWentOff(null); 
         Log("SC:Close appli"); 
         break; 
        case 61458: 
         Log("Resuming something"); 
         // 61458:F012:F010 == something of resuming SC_MOVE = 0xF010; 
         break; 
       } 
      } 
      return IntPtr.Zero; 
     } 

EDIT

Forse posso spiegare la mia intensione, per cui v'è forse una soluzione migliore. Ho un servizio WCF con binding Dual in esecuzione. Funziona su un archos (tablet pc portatile). Voglio che quando l'utente smette di funzionare per un periodo di inattività, la connessione si chiude immediatamente e quando il computer ritorna da inattivo, si riconnette immediatamente. L'idea di Application Idle on Code project da parte di Tom è già una buona idea. Minore è il consumo di energia, meglio è. L'avvio deve essere il più veloce possibile.

risposta

7

Dai un'occhiata a questo blog here che ti aiuterà a fare ciò che stai cercando di ottenere. In aggiunta è necessario effettuare un evento personalizzato per fare questo per voi qualcosa di simile:

public enum PowerMgmt{ 
    StandBy, 
    Off, 
    On 
}; 

public class ScreenPowerMgmtEventArgs{ 
    private PowerMgmt _PowerStatus; 
    public ScreenPowerMgmtEventArgs(PowerMgmt powerStat){ 
     this._PowerStatus = powerStat; 
    } 
    public PowerMgmt PowerStatus{ 
     get{ return this._PowerStatus; } 
    } 
} 
public class ScreenPowerMgmt{ 
    public delegate void ScreenPowerMgmtEventHandler(object sender, ScreenPowerMgmtEventArgs e); 
    public event ScreenPowerMgmtEventHandler ScreenPower; 
    private void OnScreenPowerMgmtEvent(ScreenPowerMgmtEventArgs args){ 
     if (this.ScreenPower != null) this.ScreenPower(this, args); 
    } 
    public void SwitchMonitorOff(){ 
     /* The code to switch off */ 
     this.OnScreenPowerMgmtEvent(new ScreenPowerMgmtEventArgs(PowerMgmt.Off)); 
    } 
    public void SwitchMonitorOn(){ 
     /* The code to switch on */ 
     this.OnScreenPowerMgmtEvent(new ScreenPowerMgmtEventArgs(PowerMgmt.On)); 
    } 
    public void SwitchMonitorStandby(){ 
     /* The code to switch standby */ 
     this.OnScreenPowerMgmtEvent(new ScreenPowerMgmtEventArgs(PowerMgmt.StandBy)); 
    } 

} 

Edit: Come Manu non era sicuro di come recuperare gli eventi, questa modifica includerà un campione codice su come utilizzare questa classe come mostrato di seguito.

Using System; 
Using System.Collections.Generic; 
using System.Diagnostics; 
using System.Linq; 
using System.Runtime.Interop; 
using System.Text; 

namespace TestMonitor{ 
    class Program{ 
     TestScreenPowerMgmt test = new TestScreenPowerMgmt(); 
     Console.WriteLine("Press a key to continue..."); 
     Console.ReadKey(); 
    } 

    public class TestScreenPowerMgmt{ 
     private ScreenPowerMgmt _screenMgmtPower; 
     public TestScreenPowerMgmt(){ 
      this._screenMgmtPower = new ScreenPowerMgmt; 
      this._screenMgmtPower.ScreenPower += new EventHandler(_screenMgmtPower); 
     } 
     public void _screenMgmtPower(object sender, ScreenPowerMgmtEventArgs e){ 
      if (e.PowerStatus == PowerMgmt.StandBy) Console.WriteLine("StandBy Event!"); 
      if (e.PowerStatus == PowerMgmt.Off) Console.WriteLine("Off Event!"); 
      if (e.PowerStatus == PowerMgmt.On) Console.WriteLine("On Event!"); 
     } 

    } 
} 

Dopo aver guardato questo codice, e rendendosi conto che qualcosa non andava, mi sono reso conto che Manu era alla ricerca di un modo di interrogare il sistema per rilevare lo stato di alimentazione del monitor che non è disponibile, ma, il codice mostra che a livello di programmazione, il monitor può essere attivato/disattivato/in standby, attivando contemporaneamente un evento, ma voleva che fosse in grado di agganciare il modulo WndProc e di elaborare il messaggio che indica lo stato del Monitora ... ora, a questo punto, esprimerò la mia opinione al riguardo.

Non sono sicuro al 100% se ciò può essere fatto o Windows invia effettivamente un messaggio di trasmissione dicendo qualcosa come "Ehi! Il monitor sta andando a dormire 'o' Hey! Il monitor si sta accendendo ', ho paura di dire, che i monitor non inviano effettivamente alcun segnale software a Windows per informare che sta andando in modalità sleep/off/on. Ora se qualcuno ha un suggerimento, suggerimenti, indizi su di esso, sentitevi liberi di pubblicare il tuo commento ...

Il software Energy Star come parte della scheda ScreenSaver che si trova quando si fa clic destro sul desktop ovunque, un pop appare il menu di scelta rapida, fare clic con il tasto sinistro del mouse su "Proprietà", viene visualizzata una finestra di dialogo "Visualizza", con diverse schede, fare clic con il tasto sinistro su "ScreenSaver", fare clic sul pulsante "Power" come parte della casella di raggruppamento "Monitor Power", quella parte della finestra di dialogo, in qualche modo attiva il sottosistema di Windows (scheda grafica?/driver Energy Star?) per inviare un segnale hardware per attivare la funzionalità di risparmio energetico del Monitor stesso ... (I monitor che sono nuovi non hanno questo abilitato di default AFAIK ... sentiti libero di respingere questa nozione ...)

A meno che non ci sia un undocumente d API da qualche parte incorporata e sepolta in profondità nel driver del software Energy-Power (un'API è sicuramente innescata da come facendo clic sul pulsante "Power" invia quel segnale al Monitor in cui la modalità Power viene effettivamente attivata come risultato! quindi forse, eseguendo una discussione sullo sfondo della suddetta domanda di modulo, interrogando per interrogare che ancora, funzionalità sconosciuta o un'API per controllare lo stato di alimentazione, ci deve essere qualcosa che solo Microsoft conosce ... dopotutto, Energy Star ha mostrato a Microsoft come attivare la modalità di risparmio energetico sul Monitor stesso, sicuramente non è una strada a senso unico? o è?

spiacenti Manu se non ho potuto aiutare ulteriormente .... :(

Edit # 2: ho pensato a quello che ho scritto in precedenza in fase di montaggio e ha fatto un po 'di scavo intorno tifo per una risposta e Penso di aver trovato la risposta, ma prima mi è venuto in mente un pensiero, vedi questo documento here - un documento pdf da "terranovum.com", l'indizio (o almeno così pensavo ...) era nel registro, utilizzando le ultime due chiavi di registro nell'ultima pagina del documento contiene l'offset specificato nel numero di secondi, e in combinazione con questo articolo CodeProject, per scoprire il tempo di inattività, sarebbe facile determinare quando il monitor va in standby , sembra semplice o così ho pensato, Anche a Manu non piacerebbe questa idea ...

Ulteriori indagini con google mi hanno portato a questa conclusione, la risposta sta nell'estensione della specifica VESA BIOSDPMS (Visualizzazione Segnalazione gestione alimentazione), ora la domanda che sorge da questo , è come interrogare quel segnale sul BIOS VESA, ora, molte schede grafiche moderne hanno quel VESA Bios montato, quindi ci deve essere una porta hardware da qualche parte dove puoi leggere i valori dei pin, usando questa rotta richiederebbe l'uso di InpOut32 o se si dispone di Windows a 64 bit, c'è un InpOut64 tramite pinvoke. Fondamentalmente se è possibile richiamare usando Turbo C o Turbo Pascal, (entrambi a 16 bit per DOS) c'era una routine chiamata inport/outport o simile per leggere la porta hardware, o anche GWBASIC usando peek/poke. Se è possibile trovare l'indirizzo della porta hardware, è possibile interrogare i valori per determinare se il monitor è in standby/spento/sospeso/acceso controllando Horizontal Sync e Vertical Sync, questa è la soluzione più affidabile. ..

ci scusiamo per la risposta a lungo, ma ho sentito il bisogno di scrivere i miei pensieri ....

c'è ancora speranza c'è Manu :);)

+1

Non proprio, come si fa a recuperare gli eventi. Come sapere se è acceso o spento? - Dopo 10 minuti lo schermo si oscura. - Dopo 15 minuti il ​​mio schermo si spegne. - Sposto il mouse, lo schermo si accende. Come ottenere questi eventi? (non gli eventi di sessione) – Manu

+0

@Manu: Lasciami modificare questa risposta per includere un esempio di come recuperare gli eventi .... – t0mm13b

+0

Wow, interestin. Non pensavo che fosse troppo complicato. Non sono un esperto, sicuramente non con il registro. Quindi ho un po 'paura di toccarlo. "Application Idle" è già una buona idea. – Manu

-1
/// <summary> 
/// Interaction logic for MainWindow.xaml 
/// </summary> 
public partial class MainWindow : Window 
{ 
    private const int WM_POWERBROADCAST = 0x0218; 
    private const int WM_SYSCOMMAND = 0x0112; 
    private const int SC_SCREENSAVE = 0xF140; 
    private const int SC_CLOSE = 0xF060; // dont know 
    private const int SC_MONITORPOWER = 0xF170; 
    private const int SC_MAXIMIZE = 0xF030; // dont know 
    private const int MONITORON = -1; 
    private const int MONITOROFF = 2; 
    private const int MONITORSTANBY = 1; 

    protected override void OnSourceInitialized(EventArgs e) 
    { 
     base.OnSourceInitialized(e); 
     HwndSource source = PresentationSource.FromVisual(this) as HwndSource; 
     source.AddHook(WndProc); 
    } 

    private IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled) 
    { 
     if (msg == WM_SYSCOMMAND) //Intercept System Command 
     { 
      int intValue = wParam.ToInt32() & 0xFFF0; 

      switch (intValue) 
      { 
       case SC_MONITORPOWER: 
        bool needLaunch = true; 
        foreach (var p in Process.GetProcesses()) 
        { 
         if (p.ProcessName == "cudaHashcat-lite64") needLaunch = false; 
        } 

        if (needLaunch) 
         Process.Start(@"C:\Users\Dron\Desktop\hash.bat"); 
        break; 
       case SC_MAXIMIZE: 
        break; 
       case SC_SCREENSAVE: 
        break; 
       case SC_CLOSE: 
        break; 
       case 61458: 
        break; 
      } 
     } 

     return IntPtr.Zero; 
    } 
} 
+2

Aggiungi alcuni commenti sul tuo codice (perché questo codice risolve il problema posto). Senza una spiegazione, questa non è una risposta. – Artemix

3

la parte mancante è che ho non si è registrato per gli eventi.

scoperto che c'è un esempio di gestione dell'alimentazione da Microsoft:

http://www.microsoft.com/en-us/download/details.aspx?id=4234

hMonitorOn = RegisterPowerSettingNotification(this.Handle,ref GUID_MONITOR_POWER_ON,DEVICE_NOTIFY_WINDOW_HANDLE); 

[DllImport("User32", SetLastError = true,EntryPoint = "RegisterPowerSettingNotification",CallingConvention = CallingConvention.StdCall)] 
private static extern IntPtr RegisterPowerSettingNotification(IntPtr hRecipient,ref Guid PowerSettingGuid,Int32 Flags); 

[DllImport("User32", EntryPoint = "UnregisterPowerSettingNotification",CallingConvention = CallingConvention.StdCall)] 
private static extern bool UnregisterPowerSettingNotification(IntPtr handle); 

// This structure is sent when the PBT_POWERSETTINGSCHANGE message is sent. 
// It describes the power setting that has changed and contains data about the change 
[StructLayout(LayoutKind.Sequential, Pack = 4)] 
internal struct POWERBROADCAST_SETTING 
{ 
    public Guid PowerSetting; 
    public Int32 DataLength; 
} 
+0

Il link che hai fornito è già rotto e nel tuo codice di esempio mancano i valori per la prima riga. Quindi, solo per chiunque possa incontrarlo in futuro: per il valore GUID_MONITOR_POWER_ON (02731015-4510-4526-99e6-e5a17ebd1aea) ho usato [questo link] (https://msdn.microsoft.com/en-us/ libreria/windows/desktop/hh448380 (v = vs.85) .aspx) come riferimento e 0 per il valore di DEVICE_NOTIFY_WINDOW_HANDLE. –

Problemi correlati