在Delphi中使用Windows Service应用程序时,我偶然发现了该主题中的问题。

我确实在IDE上启动了一个默认的Delphi Windows Service项目,按照向导进行操作,最后我有了一个项目和一个
TService单元。我向该项目添加了另一个单元,即其中包含服务代码逻辑的数据模块(名为DM)。
DM具有运行相对较长时间的TTimer(设计时)。

情况1:
DM是在设计时默认创建的。我的TService开始/停止中有以下代码

procedure TOmegaCAOraNT.ServiceStart(Sender: TService;
  var Started: Boolean);
begin
  DM.Timer1.Enabled := True;
  Started := true;
end;

procedure TOmegaCAOraNT.ServiceStop(Sender: TService; var Stopped: Boolean);
begin
  DM.Agent_Stop;
  Stopped := true;
end;


当我尝试通过Windows SCM停止服务时-从外观上确认停止,状态字段变为空-但事实并非如此。
我可以看到服务.exe仍然运行了一段时间,而且它确实终止了Timer在中间的长时间工作,
只做一部分!
这是不受欢迎的行为!

我在第二种情况下解决了这个问题

情况2:
DM是在运行时创建的。在DM.OnCreate上启用了计时器
我的TService开始/停止中有以下代码

procedure TOmegaCAOraNT.ServiceStart(Sender: TService; var Started: Boolean);
begin
  FDataModule := TDM.Create(nil);
  Started := true;
end;

procedure TOmegaCAOraNT.ServiceStop(Sender: TService; var Stopped: Boolean);
begin
  FreeAndNil(FDataModule);
  Stopped := true;
end;


当我尝试通过Windows SCM停止服务时-抛出以下警告:


“ Windows无法停止本地计算机上的SERVICE>服务。
该服务未返回错误。他的原因可能是Windows内部错误或内部服务错误。
如果错误仍然存​​在,请与系统管理员联系。”


字段状态保持已启动。计时器的长时间工作结束,直到结束,然后该服务真正停止(在SCM中刷新以查看,状态为空)
这是期望的行为!

我的问题是我希望在设计时而不是在运行时创建DM。

我的问题是:
我能否在设计时DM(案例1)中具有运行时DM(案例2)的正确行为?

感谢和最诚挚的问候,
阿尔丁

最佳答案

TService在运行时在其自己的工作线程中运行。

如果将DM配置为自动创建,则会在运行时在主线程中而不是在服务线程中创建它(及其TTimer)。因此,TTimer将在主线程中运行,并且只能由主线程激活,而不能在TService.OnStart事件处理程序中激活(如果尝试,将引发EOutOfResources异常)。

如果您在TService.OnStart事件处理程序中手动创建DM,它将在服务线程中而不是在主线程中创建它(及其TTimer)。 TTimer将在服务线程中运行,并且可以在TService事件中被(取消激活)。

无论哪种方式,请确保您的TTimer.OnTimer事件处理程序使用线程安全代码。

同样,TService.OnStop事件处理程序必须定期(在TService.ReportStatus()间隔过去之前)调用TService.WaitHint方法,同时等待其他线程停止正在执行的操作。这意味着您不应在TService.OnStop事件处理程序中使用线程阻止代码。

您没有正确处理此问题,这就是SCM出现问题的原因。

10-07 19:10