我想在计算机电源发生变化时收到通知。
首先,我创建了一个简单的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.
答案 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.