在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出现问题的原因。