1

我想在 Delphi 中制作服务应用程序,每天下午 02:00 运行和复制一些文件。所以我使用了计时器。但控制不去定时器事件和服务在 15 秒内终止。我写了一个关于 Timer Event 的代码。我如何在服务中使用计时器?请帮忙。提前致谢。

我的代码在这里:

unit untMain;

interface

uses
Winapi.Windows, Winapi.Messages, System.SysUtils, System.Classes, Vcl.Graphics,
Vcl.Controls, Vcl.SvcMgr, Vcl.Dialogs, Vcl.ExtCtrls, DateUtils, Vcl.Forms,
untCommon;

type
TsrvBackupService = class(TService)
tmrCopy: TTimer;
procedure tmrCopyTimer(Sender: TObject);

private
strlstFiles : TStringList;
{ Private declarations }
public
{ Public declarations }
end;

var
srvBackupService: TsrvBackupService;

implementation

{$R *.DFM}

procedure ServiceController(CtrlCode: DWord); stdcall;
begin
srvBackupService.Controller(CtrlCode);
end;


procedure TsrvBackupService.tmrCopyTimer(Sender: TObject);
var
strCurTime   : string;
strBKPpath   : string;
strBKPTime   : string;
NowDay       : word;
NowMonth     : word;
NowYear      : word;
NowHour      : word;
NowMin       : word;
NowSec       : word;
NowMilli     : Word;
begin
  DecodeTime(now,NowHour,NowMin,NowSec,NowMilli);
  strCurTime := IntToStr(NowHour)+':'+IntToStr(NowMin);
  strBKPTime := '14:00'
  strBKPpath := ExtractFilePath(Application.ExeName);
  if strCurTime = strBKPTime then begin
     Try
           CopyFile(PChar('c:\datafile.doc'),PChar(strBKPpath + 'datafile.doc'),true);
     except
        on l_e: exception do begin
           MessageDlg(l_E.Message,mtError,[mbOk],0);
        end;
     end;
  end;
end;

end.
4

3 回答 3

6

代替计时器,使用在 OnStart 事件中启动的简单线程。

教程在这里:

http://www.tolderlund.eu/delphi/service/service.htm

TTimer 更适合 GUI 应用程序。他们需要一个消息泵(见这里):

TTimer 需要一个正在运行的消息队列,以便接收允许操作系统将消息传递给 HWND 的 WM_TIMER 消息,或触发指定的回调

于 2012-09-15T12:27:11.380 回答
1

正如其他人所解释的那样,您不能简单地TTimer在 Windows 服务应用程序中使用组件,因为它依赖于默认情况下不在服务中的消息泵。我看到四个主要选项:

  1. 实现一个消息泵TTimer,以便能够使用
  2. 使用线程不断检查日期/时间
  3. 就像 #2 一样,使用服务的OnExecute事件来检查日期/时间
  4. 利用 Windows 的计划任务

我会推荐上面的#2,这就是原因。

#1对于您的情况可能有点多,我敢肯定您不想走那么远。

#3 可能更容易,但服务的线程需要一些特殊处理,我也确信你不需要关心。

#4 可能是理想的解决方案,但我不会试图改变您对服务的决定。

创建线程是可行的方法,因为它相当简单且可扩展。我所有的服务应用程序都在多线程基础上工作,除了处理实际服务之外,没有任何东西进入实际服务的线程。

我正在为你制作一个样本,但我把它弄得太复杂了,把它包括在这里会造成很多污染。我希望至少我能让你朝着正确的方向前进。

于 2012-09-17T09:50:30.037 回答
1

当您说“服务在 15 秒后终止”时,我觉得您正在调试代码。

如果您没有任何选项并且无法使用其他人的建议,那么当您通过 services.msc 安装和启动服务时,计时器事件会正确触发。但是,如果您正在调试服务,则不会触发计时器事件并且应用程序将终止(如您所说)。我将创建一个在计时器事件中调用的过程,并在 ServiceExecute 事件中调用它一次,因此您可以像这样调试:

procedure TSomeService.ServiceExecute(Sender: TService);
begin
  ExecuteSomeProcess(); // Put breakpoint here to debug
  while not self.Terminated do
    ServiceThread.ProcessRequests(true);
end;

procedure TSomeService.TimerTimer(Sender: TObject);
begin
  timer.Enabled := false;
  ExecuteSomeProcess(); // This can't throw any exception!
  timer.Enabled := true;
end;
于 2015-02-23T13:12:06.813 回答