我想请您提供一些建议,关于一个问题。
我创建了一个Windows服务,用于管理我的应用程序的任务。
该服务连接到数据库(Firebird),并调用一个组件来进行任务管理。
这个过程正常运行,然而,在Windows 10上,计算机重新启动后该服务不会自动启动。在其他版本的Windows中,一切都完美地运行。在测试中,我已经确定,如果我注释掉调用任务执行方法的代码,服务通常会在Windows 10上启动。
Procedure TDmTaskService.ServiceExecute(Sender: TService);
Begin
Inherited;
While Not Terminated Do
Begin
//Process;
Sleep(3000);
ServiceThread.ProcessRequests(False);
End;
End;
问题在于组件或服务中未生成任何异常。
通过分析Windows事件监视器,我已经确定了发生在我的服务上的错误是超时,这种情况下服务无法在时间限制内连接到服务管理器。不再生成更多的异常。
有人对使用Delphi制作连接到数据库的Windows服务有什么建议吗?
以下是我的源代码示例:
**Base class:**
unit UnTaskServiceDmBase;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, SvcMgr, Dialogs;
type
TDmTaskServicosBase = class(TService)
private
{ Private declarations }
public
function GetServiceController: TServiceController; override;
{ Public declarations }
end;
var
DmTaskServiceBase: TDmTaskServicosBase;
implementation
{$R *.DFM}
procedure ServiceController(CtrlCode: DWord); stdcall;
begin
DmJBServicosBase.Controller(CtrlCode);
end;
function TDmTaskServicosBase.GetServiceController: TServiceController;
begin
Result := ServiceController;
end;
end.
**Service Class:**
Unit UnTaskServiceDm;
Interface
Uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, SvcMgr, Dialogs,
UnJBTask,
UnJBReturnTypes,
UnJBUtilsFilesLog,
UnTaskServiceDmConfig,
UnTaskServiceDmConnection,
ExtCtrls,
IniFiles;
Type
TDmTaskService = Class(TDmTaskServicosBase)
Procedure ServiceExecute(Sender: TService);
Procedure ServiceCreate(Sender: TObject);
Procedure ServiceStop(Sender: TService; Var Stopped: Boolean);
Private
FTaskServiceConfig: TDmTaskServiceConfig;
FStatus: TResultStatus;
FDmConnection: TDmTaskServiceConnection;
FJBTask: TJBTask;
FLog: TJBUtilsFilesLog;
Procedure ExecuteTasksSchedule;
Procedure UpdateServiceInformation;
Procedure Process;
Procedure UpdateConnection;
Public
Function GetServiceController: TServiceController; Override;
End;
Implementation
{$R *.DFM}
Procedure ServiceController(CtrlCode: DWord); Stdcall;
Begin
DmTaskService.Controller(CtrlCode);
End;
Procedure TDmTaskService.UpdateConnection;
Begin
Try
FDmConnection.SqcCon.Connected := False;
FDmConnection.SqcCon.Connected := True;
FLog.Adicionar('Conexão com banco restabelecida.');
FLog.FinalizarLog;
Except
On E: Exception Do
Begin
FLog.Adicionar('Erro ao restabelecer conexão com o banco de dados.' +
sLineBreak + sLineBreak + E.Message);
FLog.FinalizarLog;
End;
End;
End;
Procedure TDmTaskService.UpdateServiceInformation;
Begin
Inherited;
Try
Try
FTaskServiceConfig.Load;
FLog.Adicionar('Dados registro serviço.');
FLog.Adicionar('Nome: ' + FTaskServiceConfig.ServiceName);
FLog.Adicionar('Descrição: ' + FTaskServiceConfig.ServiceDescription);
If (FTaskServiceConfig.ServiceName <> EmptyStr) And
(FTaskServiceConfig.ServiceDescription <> EmptyStr) Then
Begin
Name := FTaskServiceConfig.ServiceName ;
DisplayName := FTaskServiceConfig.ServiceDescription;
End;
FTaskServiceConfig.Close;
Except
On E: Exception Do
Begin
FLog.Adicionar('Erro adicionar dados registro serviço.');
FLog.Adicionar('Erro ocorrido: ' + sLineBreak + sLineBreak + E.Message);
End;
End;
Finally
FLog.Adicionar('Name: ' + Name);
FLog.Adicionar('DisplayName: ' + DisplayName);
FLog.FinalizarLog;
End;
End;
Procedure TDmTaskService.Process;
Begin
Try
If FDmConnection.SqcCon.Connected Then
Begin
ExecuteTasksSchedule;
End
Else
UpdateConnection;
Except
On E: Exception Do
Begin
FLog.Adicionar('Ocorreu um erro ao checar as tarefas.' + sLineBreak +
'Erro ocorrido: ' + sLineBreak + E.Message);
FLog.FinalizarLog;
UpdateConnection;
End;
End;
End;
Procedure TDmTaskService.ExecutarTarefasAgendadas;
Begin
If FJBTask.ExistTaskDelayed Then
Begin
Try
FJBTask.ExecuteTasks;
Except
On E: Exception Do
Begin
FLog.Adicionar('Ocorreu um erro ao executar as tarefas agendadas.' +
sLineBreak + 'Erro ocorrido: ' + sLineBreak + E.Message);
FLog.FinalizarLog;
UpdateConnection;
End;
End;
End;
End;
Function TDmTaskService.GetServiceController: TServiceController;
Begin
Result := ServiceController;
End;
Procedure TDmTaskService.ServiceCreate(Sender: TObject);
Begin
Inherited;
Try
FLog := TJBUtilsFilesLog.Create;
FLog.ArquivoLog := IncludeTrailingPathDelimiter(FLog.LogFolder) + 'TaksService.log';
FDmConnection := TDmTaskServiceConexao.Create(Self);
FDmConnection.Log := FLog;
FJBTask := TJBTarefa.Create(Self);
FJBTask.SQLConnection := FDmConnection.SqcConexao;
FTaskServiceConfig := TDmTaskServiceConfig.Create(Self);
FTaskServiceConfig.SQLConnection := FDmConnection.SqcConexao;
FStatus := FDmConnection.ConfigurouConexao;
If FStatus.ResultValue Then
Begin
UpdateServiceInformation;
End
Else
Begin
FLog.Adicionar(FStatus.MessageOut);
FLog.FinalizarLog;
End;
Except
On E: Exception Do
Begin
FLog.Adicionar('Não foi possível iniciar o serviço.' + sLineBreak +
'Erro ocorrido: ' + sLineBreak + sLineBreak + E.Message);
FLog.FinalizarLog;
Abort;
End;
End;
End;
Procedure TDmTaskService.ServiceExecute(Sender: TService);
Begin
Inherited;
While Not Terminated Do
Begin
Process;
Sleep(3000);
ServiceThread.ProcessRequests(False);
End;
End;
Procedure TDmTaskService.ServiceStop(Sender: TService; Var Stopped: Boolean);
Begin
Inherited;
If Assigned(FDmConnection) Then
Begin
FLog.Adicionar('Finalizando serviço.');
FLog.Adicionar('Fechando conexão.');
Try
FDmConnection.SqcConexao.Close;
Finally
FLog.FinalizarLog;
End;
End;
End;
End.
Sleep(3000);
容易引起麻烦——在服务和线程中绝对不推荐这样做。至少应该用循环实现,并持续检查是否已终止。 - Jerry DodgeInherited;
,这告诉我你的整个服务数据模块是从另一个继承而来的,可能有更多的代码。你的问题可能在那个祖先代码中。但是,它并没有被继承,直接在那里有TService
,所以我不知道为什么你到处都有Inherited;
。 - Jerry Dodge