2017-02-16 2 views
0

Вот кодНевозможно зарегистрировать для настройки уведомлений питания в WinForms C#

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

    static Guid GUID_LIDSWITCH_STATE_CHANGE = new Guid(0xBA3E0F4D, 0xB817, 0x4094, 0xA2, 0xD1, 0xD5, 0x63, 0x79, 0xE6, 0xA0, 0xF3); 
    private const int DEVICE_NOTIFY_WINDOW_HANDLE = 0x00000000; 
    private const int WM_POWERBROADCAST = 0x0218; 
    const int PBT_POWERSETTINGCHANGE = 0x8013; 

    [StructLayout(LayoutKind.Sequential, Pack = 4)] 
    internal struct POWERBROADCAST_SETTING 
    { 
     public Guid PowerSetting; 
     public uint DataLength; 
     public byte Data; 
    } 

    private bool? _previousLidState = null; 


    public TrayIcon() 
    { 
     RegisterForPowerNotifications(); 

    } 

    [SecurityPermissionAttribute(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.UnmanagedCode)] 
    protected override void WndProc(ref Message m) 
    { 
     switch (m.Msg) 
     { 
      case WM_POWERBROADCAST: 
       OnPowerBroadcast(m.WParam, m.LParam); 
       break; 
      default: 
       break; 
     } 
     base.WndProc(ref m); 
    } 


    private void RegisterForPowerNotifications() 
    { 
     IntPtr handle = this.Handle; 
     Debug.WriteLine("Handle: " + handle.ToString()); //If this line is omitted, then lastError = 1008 which is ERROR_NO_TOKEN, otherwise, lastError = 0 
     IntPtr hLIDSWITCHSTATECHANGE = RegisterPowerSettingNotification(handle, 
      ref GUID_LIDSWITCH_STATE_CHANGE, 
      DEVICE_NOTIFY_WINDOW_HANDLE); 
     Debug.WriteLine("Registered: " + hLIDSWITCHSTATECHANGE.ToString()); 
     Debug.WriteLine("LastError:" + Marshal.GetLastWin32Error().ToString()); 
    } 

    private void OnPowerBroadcast(IntPtr wParam, IntPtr lParam) 
    { 
     if ((int)wParam == PBT_POWERSETTINGCHANGE) 
     { 
      POWERBROADCAST_SETTING ps = (POWERBROADCAST_SETTING)Marshal.PtrToStructure(lParam, typeof(POWERBROADCAST_SETTING)); 
      IntPtr pData = (IntPtr)((int)lParam + Marshal.SizeOf(ps)); 
      Int32 iData = (Int32)Marshal.PtrToStructure(pData, typeof(Int32)); 
      if (ps.PowerSetting == GUID_LIDSWITCH_STATE_CHANGE) 
      { 
       bool isLidOpen = ps.Data != 0; 

       if (!isLidOpen == _previousLidState) 
       { 
        LidStatusChanged(isLidOpen); 
       } 

       _previousLidState = isLidOpen; 
      } 
     } 
    } 

    private void LidStatusChanged(bool isLidOpen) 
    { 
     if (isLidOpen) 
     { 
      //Do some action on lid open event 
      MessageBox.Show("Lid is now open"); 
     } 
     else 
     { 
      //Do some action on lid close event 
      MessageBox.Show("Lid is now closed"); 
     } 
    } 
} 
} 

Я понятия не имею, что проблема есть. Я звоню на WndProc, но ничего не происходит, когда крышка закрыта или открыта. LidStatusChanged никогда не называется.

Я следил за this post, но это не помогает, поскольку все соответствует.

Я понятия не имею, что, черт возьми, я сделал не так. Вся помощь очень ценится.

+1

Можем ли мы иметь [mcve]? Он становится минимальным, когда вы больше не можете удалять код, демонстрирующий поведение. – IInspectable

+0

@ Необычный, удаленный, что я мог. Все, что я опубликовал, необходимо для того, чтобы показать, что поведение, которое передается в эфир, никогда не отправляется в мое приложение. – Seth

+0

Вы также можете подумать о том, имеет ли смысл перемещать часть этого кода на C++/CLI, чтобы вам не пришлось копировать столько материалов из файлов Windows ** .h **. –

ответ

3
ShowInTaskbar = Visible = false; 

Эта ошибка больше не отображается во фрагменте. Это вызвало проблему с назначением свойств ShowInTaskbar. Это «трудное» свойство, оно может быть указано только в флажках стиля, переданных CreateWindowEx(). Чтобы заставить Winforms уничтожить текущее окно и создать новый, теперь он получает другое значение Handle. Больше никаких уведомлений.

Возможно, вы попали в эту проблему, пытаясь сохранить невидимое окно. Правильный способ сделать это:

protected override void SetVisibleCore(bool value) { 
    if (!IsHandleCreated) { 
     this.CreateHandle(); 
     value = false; 
    } 
    base.SetVisibleCore(value); 
} 

Удалить OnLoad(), больше не нужно и не называется, пока окно фактически становится видимым. И вы хотите убедиться, что даже если значение Handle по какой-то причине изменилось (существует несколько «сложных» свойств), вы все равно получите уведомление. Что вы делаете, удалив код из конструктора и:

protected override void OnHandleCreated(EventArgs e) { 
    base.OnHandleCreated(e); 
    RegisterForPowerNotifications(); 
} 
+0

Aha. У меня возникло чувство, что это будет проблемой. Так как это работало, когда я прокомментировал строку «ShowInTaskbar = Visible = false;». Но не знал, как добиться желаемого эффекта. Спасибо огромное! Отмечено как решение, которое прекрасно работает! Спасибо за новую информацию о 'SetVisibleCore', я очень благодарен! – Seth