2017-02-16 10 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

@IInspectable,刪除了我所能。我發佈的所有內容都是展示電源廣播永遠不會發送到我的應用的行爲所必需的。 – 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

啊哈。我有一種感覺,那就是問題..當我註釋掉'ShowInTaskbar = Visible = false;'行時,它確實有效。但不知道如何獲得理想的效果。非常感謝你!標記爲解決方案,因爲它的工作非常好!感謝有關'SetVisibleCore'的新信息,我非常感謝! – Seth