【问题标题】:Service exe does not receive power events服务 exe 未收到电源事件
【发布时间】:2015-03-08 12:55:47
【问题描述】:

我创建了一个将在启动时自动运行的服务 exe。

我正在使用这个例子来创建服务: http://www.cromis.net/blog/2011/04/how-to-make-a-very-small-windows-service-executable/

效果很好。该服务需要“监控”PC 的状态,例如检查 PC 是否连接到电源。如果发生变化,例如从连接电源变为电池或电池电量不足,它将发送有关设备严重状态的紧急电子邮件。

当作为普通 exe 而不是作为服务运行时,这非常有效。目标是能够在 PC 的任何状态(登录或未登录)下执行此操作,因此必须作为服务运行。

我已经创建了一个窗口句柄来接收 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() 轮询消息,但结果是相同的。

我可以做些什么来捕捉 powerstate 事件?服务无法对电源状态更改做出反应,这有点奇怪?

【问题讨论】:

  • 询问 WMI -> Win32_Battery
  • 您需要“Ex”版本 (RegisterServiceCtrlHandlerEx),而不是消息泵和窗口。请参阅文档。
  • 请原谅我的回复晚了,但有人可以向我解释一下为什么对这个问题投反对票是值得的吗?

标签: windows api delphi service power-state


【解决方案1】:

当服务使用SERVICE_ACCEPT_POWEREVENT 时,服务必须通过RegisterServiceCtrlHandlerEx() 使用HandlerEx() 回调来接收来自SCM 的SERVICE_CONTROL_POWEREVENT 通知。但是,您链接到的示例代码(以及 Delphi 自己的 TService 框架)通过 RegisterServiceCtrlHandler() 使用过时的 Handler() 回调,它不会收到此类通知。因此,您需要更新代码以改用HandlerEx() 回调。

或者,要在不使用 SCM 回调的情况下接收电源通知,请查看 RegisterPowerSettingNotification()PowerSettingRegisterNotification(),它们可以分别将电源通知发送到 HWND 或回调函数。

【讨论】:

  • 问题中的链接没有使用TService,RegisterServiceCtrlHandlerEx是一个有效的解决方案。
  • 链接代码遇到了与TService 相同的问题。我已经更新了我的答案以反映这一点。
  • 不幸的是,我一年前的 QC #124304 条目仍处于“已报告”状态,不知道是否已在新的错误跟踪器中移动。我还看到 Lebeau 在 2002 年提交了一个类似的(#287 !),尽管对于 C++ Builder,并且从那时起它是“开放的”......也许我们有机会在 Delphi X80 Emb 中将 TService 更新为 Windows 2000 引入的 API。 ..
  • QC #124304 不在新的 QP 系统中。您应提交新的 QP 票证并在其中提及原始 QC 票证。在任何情况下,QC 和 QP 都链接到同一个内部错误跟踪系统(尽管它看起来不像 QC #124304 被推入其中)。 EMBT 开发人员仍然可以看到 QC 报告。至于TService 在 XE8 中更新,自从XE8 is already in beta 之后发生这种情况的可能性很小。
  • @Lebeau:我想我应该向他们提交我的 TServiceEx 实现,该实现正是支持“新”功能所需的。不幸的是我不能分享它,因为我不能简单地从 TService 继承并修改它的行为,太多的私有字段和函数,甚至尝试使用类帮助器注入一些代码都不起作用,我不得不修改 TService 代码(在这里你可以找到我所做的一些更改:sandon.it/?q=node/97) 反正我写的是 X8*0*,这不是打字错误……过去十三年没修好,还需要很多年待修复....
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-03-25
  • 2018-03-01
  • 1970-01-01
  • 2014-09-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多