Служба EXE не получает события питания
Я создал сервис exe, который будет автоматически запускаться при загрузке.
Я использую этот пример для создания сервиса: http://www.cromis.net/blog/2011/04/how-to-make-a-very-small-windows-service-executable/
Работает довольно хорошо. Служба должна "контролировать" состояние ПК, например, чтобы проверить, подключен ли ПК к источнику питания или нет. В случае изменения, например, от подключенного питания к аккумулятору или низкого уровня заряда аккумулятора, он отправит экстренное электронное письмо о критическом состоянии устройства.
Это работает довольно хорошо, когда работает как обычный exe, но не как служба. Цель состоит в том, чтобы иметь возможность делать это в любом состоянии компьютера (вошел в систему или нет), поэтому важно работать как служба.
Я создал дескриптор окна для получения сообщения WM_POWERBROADCAST, например:
procedure TEventAlerter.wndProc(var Msg : TMessage);
var
handled: Boolean;
begin
log( 'wndProc processed - '+intToStr( Msg.Msg ));
// Assume we handle message
handled := TRUE;
case( Msg.Msg ) of
WM_POWERBROADCAST : begin
case( Msg.WParam ) of
PBT_APMPOWERSTATUSCHANGE : powerChangeEvent(Msg.WParam);
PBT_APMBATTERYLOW : powerLowEvent(Msg.WParam);
else powerEvent(Msg.WParam);
end;
end;
else handled:= FALSE;
end;
if( handled ) then
begin
// We handled message - record in message result
Msg.Result := 0
end
else
begin
// We didn't handle message
// pass to DefWindowProc and record result
Msg.Result := DefWindowProc(fHWnd, Msg.Msg, Msg.WParam, Msg.LParam);
end;
end;
Для инициализации я использую это:
FHwnd:=AllocateHWnd(wndProc);
Поскольку я знаю о состоянии 0-изоляции при работе в качестве службы, я изменил пример кода функции RegisterService() следующим образом:
ServiceStatus.dwServiceType := SERVICE_WIN32_OWN_PROCESS or SERVICE_INTERACTIVE_PROCESS;
ServiceStatus.dwCurrentState := SERVICE_START_PENDING;
ServiceStatus.dwControlsAccepted := SERVICE_ACCEPT_STOP or
SERVICE_ACCEPT_PAUSE_CONTINUE or
SERVICE_ACCEPT_POWEREVENT;
Но без какого-либо успеха. Я также использую поток для опроса сообщений с помощью функции Windows API getMessage()
из окна, но результаты совпадают.
Что я могу сделать, чтобы ловить события электростанции? Это довольно странно, что сервисы не могут реагировать на изменения состояния или нет?
1 ответ
Когда служба использует SERVICE_ACCEPT_POWEREVENT
служба должна использовать HandlerEx()
обратный звонок через RegisterServiceCtrlHandlerEx()
получить SERVICE_CONTROL_POWEREVENT
уведомления от СКМ. Тем не менее, пример кода, на который вы ссылались (а также собственный Delphi TService
рамки) использует устаревшие Handler()
обратный звонок через RegisterServiceCtrlHandler()
вместо этого, который не получает такие уведомления. Так что вам нужно обновить код, чтобы использовать HandlerEx()
Обратный звонок вместо.
В качестве альтернативы, чтобы получать уведомления о мощности без использования обратного вызова SCM, взгляните на RegisterPowerSettingNotification()
или же PowerSettingRegisterNotification()
, который может отправлять уведомления о мощности в HWND или функцию обратного вызова, соответственно.