如何使用RegisterPowerSettingNotification

时间:2015-10-22 17:49:19

标签: delphi delphi-xe6

我想在计算机电源发生变化时收到通知。

首先,我创建了一个简单的Delphi应用程序并进行了监听 主要表格WM_POWERBROADCAST

WM_POWERBROADCAST

type
  TForm38 = class(TForm)
  public
    procedure WM_POWERBROADCAST(var Msg: TMessage); message WM_POWERBROADCAST;
  end;

implementation

procedure TForm38.WM_POWERBROADCAST(var Msg: TMessage);
begin
  Caption := Msg.LParam.ToString;
end;

然后我收到了通知,但Msg.LParam总是0(零)

然后我尝试拨打RegisterPowerSettingNotification并在旧的SO Question中找到了一个示例,但我仍然遇到同样的问题:Msg.LParam总是0(零)

RegisterPowerSettingNotification

type
  TForm38 = class(TForm)
    Button1: TButton;
    procedure FormCreate(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
  private
    FHPOWERNOTIFY: HPOWERNOTIFY;
  public
    { Public declarations }
    procedure WM_POWERBROADCAST(var Msg: TMessage); message WM_POWERBROADCAST;
  end;

implementation

const
  GUID_ACDC_POWER_SOURCE: TGUID = '{5D3E9A59-E9D5-4B00-A6BD-FF34FF516548}';

procedure TForm38.FormCreate(Sender: TObject);
begin
  FHPOWERNOTIFY := RegisterPowerSettingNotification(Handle, GUID_ACDC_POWER_SOURCE, DEVICE_NOTIFY_WINDOW_HANDLE);
end;

procedure TForm38.FormDestroy(Sender: TObject);
begin
  UnregisterPowerSettingNotification(FHPOWERNOTIFY);
end;

procedure TForm38.WM_POWERBROADCAST(var Msg: TMessage);
begin
  Caption := Msg.LParam.ToString;
end;

应用程序在Windows 10上运行。

我做错了什么?

结果

使用回答这个问题的代码,我最后写了这个课:

unit PowerWatcherU;

interface

uses
  Winapi.Windows, System.Classes, System.SyncObjs, Winapi.Messages;

{$M+}

type
  TPowerSource = (PoAc = 0, PoDc = 1, PoHot = 2);
  TPowerSourceChanged = procedure(const PowerSource: TPowerSource) of object;

  TPowerWatcher = class(TComponent)
  private
    FMyHWND: HWND;
    FHPOWERNOTIFY: HPOWERNOTIFY;
    FOnPowerSourceChanged: TPowerSourceChanged;
    procedure DoPowerSourceChanged(const Value: TPowerSource);
    procedure WndHandler(var Msg: TMessage);
    procedure SetOnPowerSourceChanged(const Value: TPowerSourceChanged);
  published
    property OnPowerSourceChanged: TPowerSourceChanged read FOnPowerSourceChanged write SetOnPowerSourceChanged;
  public
    constructor Create(AOwner: TComponent); override;
    destructor Destroy; override;
  end;

const
  GUID_ACDC_POWER_SOURCE: TGUID = '{5D3E9A59-E9D5-4B00-A6BD-FF34FF516548}';

implementation

uses
  System.SysUtils;

{ TPowerWatcher }

constructor TPowerWatcher.Create;
begin
  inherited;
  FMyHWND := AllocateHWND(WndHandler);
  FHPOWERNOTIFY := RegisterPowerSettingNotification(FMyHWND, GUID_ACDC_POWER_SOURCE, DEVICE_NOTIFY_WINDOW_HANDLE);
end;

destructor TPowerWatcher.Destroy;
begin
  DeallocateHWND(FMyHWND);
  UnregisterPowerSettingNotification(FHPOWERNOTIFY);
  inherited;
end;

procedure TPowerWatcher.DoPowerSourceChanged(const Value: TPowerSource);
begin
  if Assigned(FOnPowerSourceChanged) then
    FOnPowerSourceChanged(Value);
end;

procedure TPowerWatcher.SetOnPowerSourceChanged(const Value: TPowerSourceChanged);
begin
  FOnPowerSourceChanged := Value;
end;

procedure TPowerWatcher.WndHandler(var Msg: TMessage);
begin
  if (Msg.Msg = WM_POWERBROADCAST) and (Msg.WParam = PBT_POWERSETTINGCHANGE) then
  begin
    if PPowerBroadcastSetting(Msg.LParam)^.PowerSetting = GUID_ACDC_POWER_SOURCE then
      DoPowerSourceChanged(TPowerSource(PPowerBroadcastSetting(Msg.LParam)^.Data[0]));
  end
  else
    Msg.Result := DefWindowProc(FMyHWND, Msg.Msg, Msg.WParam, Msg.LParam);
end;

end.

1 个答案:

答案 0 :(得分:2)

您可能正在遭受窗口重建。您发布的代码对我来说很好,但在Win10中可能不是这样。除此之外,唯一的另一个奇怪之处在于您通过命名方法WM_POWERBROADCAST来复制标识符,尽管这不应该导致代码中断。使用专用HWND

的工作示例
unit Unit1;

interface

uses
  Windows, SysUtils, Classes, Forms, StdCtrls, Vcl.Controls, Vcl.ExtCtrls,
  Messages;

type

  TForm1 = class(TForm)
    Button1: TButton;
    procedure FormCreate(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
    private
      FMyHWND : HWND;
      FHPowerNotify: HPOWERNOTIFY;
    public
      procedure WndHandler(var Msg: TMessage);
 end;

var
  Form1: TForm1;

implementation
{$R *.dfm}

const
  GUID_ACDC_POWER_SOURCE: TGUID = '{5D3E9A59-E9D5-4B00-A6BD-FF34FF516548}';

procedure TForm1.FormCreate(Sender: TObject);
begin
  FMyHWND := AllocateHWND(WndHandler);
  FHPowerNotify := RegisterPowerSettingNotification(FMyHWND,
                                                    GUID_ACDC_POWER_SOURCE, 
                                                    DEVICE_NOTIFY_WINDOW_HANDLE);
end;

procedure TForm1.FormDestroy(Sender: TObject);
begin
  UnregisterPowerSettingNotification(FHPowerNotify);
  DeallocateHWND(FMyHWND);
end;

procedure TForm1.WndHandler(var Msg: TMessage);
begin
  if (Msg.Msg = WM_POWERBROADCAST) and
     (Msg.WParam = PBT_POWERSETTINGCHANGE) then
  begin
    if PPowerBroadcastSetting(Msg.LParam)^.PowerSetting = GUID_ACDC_POWER_SOURCE then
      case cardinal(PPowerBroadcastSetting(Msg.LParam)^.Data[0]) of
        0: Caption := 'AC Power';
        1: Caption := 'DC Power';
        2: Caption := 'HOT - UPS, etc';
      end;
  end else
    msg.Result := DefWindowProc(FMyHWND, Msg.Msg, Msg.WParam, Msg.LParam);
end;

end.
相关问题