Jer*_*dge 10 delphi service delphi-xe2
我在Delphi 7中构建了一些服务并且没有这个问题.现在我在XE2中启动了一个新的服务应用程序,它将无法正常停止.我不知道这是不是我做错了,或者它是否是XE2服务中的一个错误.
执行过程如下所示:
procedure TMySvc.ServiceExecute(Sender: TService);
begin
try
CoInitialize(nil);
Startup;
try
while not Terminated do begin
DoSomething; //Problem persists even when nothing's here
end;
finally
Cleanup;
CoUninitialize;
end;
except
on e: exception do begin
PostLog('EXCEPTION in Execute: '+e.Message);
end;
end;
end;
Run Code Online (Sandbox Code Playgroud)
我从来没有例外,因为你可以看到我记录任何异常.PostLog保存到INI文件,工作正常.现在我使用ADO组件,所以我使用CoInitialize()和CoUninitialize.它确实连接到数据库并正常工作.问题只发生在我停止此服务时.Windows给了我以下消息:

然后服务继续.我必须第二次停下来.它第二次停止,但有以下消息:

日志文件表明服务已成功释放(OnDestroy事件已记录)但它从未成功停止(OnStop从未记录).
在上面的代码中,我有两个程序Startup和Cleanup.这些只是创建/破坏和初始化/取消初始化我必要的东西......
procedure TMySvc.Startup;
begin
FUpdateThread:= TMyUpdateThread.Create;
FUpdateThread.OnLog:= LogUpdate;
FUpdateThread.Resume;
end;
procedure TMySvc.Cleanup;
begin
FUpdateThread.Terminate;
end;
Run Code Online (Sandbox Code Playgroud)
如您所见,我有一个辅助线程在运行.这个服务实际上有很多线程像这样运行,主服务线程只记录每个线程的事件.每个线程都有不同的职责.线程正确报告,并且它们也正在正确终止.
什么可能导致这种停止失败?如果我发布的代码没有公开任何内容,那么我可以在以后发布更多代码 - 只需要因为内部命名等而"转换"它.
编辑
我刚刚在Delphi XE2中启动了新服务项目,并且遇到了同样的问题.这是我的所有代码:
unit JDSvc;
interface
uses
Winapi.Windows, Winapi.Messages, System.SysUtils, System.Classes, JDSvcMgr;
type
TJDService = class(TService)
procedure ServiceExecute(Sender: TService);
private
FAfterInstall: TServiceEvent;
public
function GetServiceController: TServiceController; override;
end;
var
JDService: TJDService;
implementation
{$R *.DFM}
procedure ServiceController(CtrlCode: DWord); stdcall;
begin
JDService.Controller(CtrlCode);
end;
function TJDService.GetServiceController: TServiceController;
begin
Result := ServiceController;
end;
procedure TJDService.ServiceExecute(Sender: TService);
begin
while not Terminated do begin
end;
end;
end.
Run Code Online (Sandbox Code Playgroud)
查看Execute方法的源代码:
procedure TServiceThread.Execute;
var
msg: TMsg;
Started: Boolean;
begin
PeekMessage(msg, 0, WM_USER, WM_USER, PM_NOREMOVE); { Create message queue }
try
// Allow initialization of the Application object after
// StartServiceCtrlDispatcher to prevent conflicts under
// Windows 2003 Server when registering a class object with OLE.
if Application.DelayInitialize then
Application.Initialize;
FService.Status := csStartPending;
Started := True;
if Assigned(FService.OnStart) then FService.OnStart(FService, Started);
if not Started then Exit;
try
FService.Status := csRunning;
if Assigned(FService.OnExecute) then
FService.OnExecute(FService)
else
ProcessRequests(True);
ProcessRequests(False);
except
on E: Exception do
FService.LogMessage(Format(SServiceFailed,[SExecute, E.Message]));
end;
except
on E: Exception do
FService.LogMessage(Format(SServiceFailed,[SStart, E.Message]));
end;
end;
Run Code Online (Sandbox Code Playgroud)
正如您所看到的,如果您不分配OnExecute方法,Delphi将处理SCM请求(Service Start,Stop,...),直到服务停止.在Service.Execute中进行循环时,必须通过调用自己处理SCM请求ProcessRequests(False).一个好习惯是不要使用Service.execute并在Service.OnStart事件中启动你的workerthread并在Service.OnStop事件中终止/释放它.
正如评论中所说,另一个问题在于该FUpdateThread.Terminate部分.大卫·赫弗南(David Heffernan)在Free/WaitFor评论中名列前茅.确保使用同步对象以正确的方式结束线程.