| 一、服务程序和桌面程序的区别
 Windows 2000/XP/2003等支持一种叫做“系统服务程序”的进程,系统服务和桌面程序的区别是:
 系统服务不用登陆系统即可运行;系统服务是运行在System Idle Process/System/smss/winlogon/services下的,而桌面程序是运行在Explorer下的;系统服务拥有更高的权限,系统服务拥有Sytem的权限,而桌面程序只有Administrator权限;在Delphi中系统服务是对桌面程序进行了再一次的封装,既系统服务继承于桌面程序。因而拥有桌面程序所拥有的特性;系统服务对桌面程序的DoHandleException做了改进,会自动把异常信息写到NT服务日志中;普通应用程序启动只有一个线程,而服务启动至少含有三个线程。(服务含有三个线程:TServiceStartThread服务启动线程;TServiceThread服务运行线程;Application主线程,负责消息循环);
 摘录代码:
 procedure TServiceApplication.Run;
 begin
 .
 .
 .
 StartThread := TServiceStartThread.Create(ServiceStartTable);
 try
 while not Forms.Application.Terminated do
 Forms.Application.HandleMessage;
 Forms.Application.Terminate;
 if StartThread.ReturnValue <> 0 then
 FEventLogger.LogMessage(SysErrorMessage(StartThread.ReturnValue));
 finally
 StartThread.Free;
 end;
 .
 .
 .
 end;
 
 procedure TService.DoStart;
 begin
 try
 Status := csStartPending;
 try
 FServiceThread := TServiceThread.Create(Self);
 FServiceThread.Resume;
 FServiceThread.WaitFor;
 FreeAndNil(FServiceThread);
 finally
 Status := csStopped;
 end;
 except
 on E: Exception do
 LogMessage(Format(SServiceFailed,[SExecute, E.Message]));
 end;
 end;
 在系统服务中也可以使用TTimer这些需要消息的定时器,因为系统服务在后台使用TApplication在分发消息;
 
 二、如何编写一个系统服务
 
 打开Delphi编辑器,选择菜单中的File|New|Other...,在New Item中选择Service Application项,Delphi便自动为你建立一个基于TServiceApplication的新工程,TserviceApplication是一个封装NT服务程序的类,它包含一个TService1对象以及服务程序的装卸、注册、取消方法。
 TService属性介绍:
 AllowPause:是否允许暂停;
 AllowStop:是否允许停止;
 Dependencies:启动服务时所依赖的服务,如果依赖服务不存在则不能启动服务,而且启动本服务的时候会自动启动依赖服务;
 DisplayName:服务显示名称;
 ErrorSeverity:错误严重程度;
 Interactive:是否允许和桌面交互;
 LoadGroup:加载组;
 Name:服务名称;
 Password:服务密码;
 ServiceStartName:服务启动名称;
 ServiceType:服务类型;
 StartType:启动类型;
 事件介绍:
 AfterInstall:安装服务之后调用的方法;
 AfterUninstall:服务卸载之后调用的方法;
 BeforeInstall:服务安装之前调用的方法;
 BeforeUninstall:服务卸载之前调用的方法;
 OnContinue:服务暂停继续调用的方法;
 OnExecute:执行服务开始调用的方法;
 OnPause:暂停服务调用的方法;
 OnShutDown:关闭时调用的方法;
 OnStart:启动服务调用的方法;
 OnStop:停止服务调用的方法;
 
 三、编写一个两栖服务
 
 采用下面的方法,可以实现一个两栖系统服务(既系统服务和桌面程序的两种模式)
 工程代码:
 program FleetReportSvr;
 
 uses
 SvcMgr,
 Forms,
 SysUtils,
 Windows,
 SvrMain in 'SvrMain.pas' {FleetReportService: TService},
 AppMain in 'AppMain.pas' {FmFleetReport};
 
 {$R *.RES}
 
 const
 CSMutexName = 'Global\Services_Application_Mutex';
 var
 OneInstanceMutex: THandle;
 SecMem: SECURITY_ATTRIBUTES;
 aSD: SECURITY_DESCRIPTOR;
 begin
 InitializeSecurityDescriptor(@aSD, SECURITY_DESCRIPTOR_REVISION);
 SetSecurityDescriptorDacl(@aSD, True, nil, False);
 SecMem.nLength := SizeOf(SECURITY_ATTRIBUTES);
 SecMem.lpSecurityDescriptor := @aSD;
 SecMem.bInheritHandle := False;
 OneInstanceMutex := CreateMutex(@SecMem, False, CSMutexName);
 if (GetLastError = ERROR_ALREADY_EXISTS)then
 begin
 DlgError('Error, Program or service already running!');
 Exit;
 end;
 if FindCmdLineSwitch('svc', True) or
 FindCmdLineSwitch('install', True) or
 FindCmdLineSwitch('uninstall', True) then
 begin
 SvcMgr.Application.Initialize;
 SvcMgr.Application.CreateForm(TSvSvrMain, SvSvrMain);
 SvcMgr.Application.Run;
 end
 else
 begin
 Forms.Application.Initialize;
 Forms.Application.CreateForm(TFmFmMain, FmMain);
 Forms.Application.Run;
 end;
 end.
 然后在SvrMain注册服务:
 unit SvrMain;
 
 interface
 
 uses
 Windows, Messages, SysUtils, Classes, Graphics, Controls, SvcMgr, Dialogs, MsgCenter;
 
 type
 TSvSvrMain = class(TService)
 procedure ServiceStart(Sender: TService; var Started: Boolean);
 procedure ServiceStop(Sender: TService; var Stopped: Boolean);
 procedure ServiceBeforeInstall(Sender: TService);
 procedure ServiceAfterInstall(Sender: TService);
 private
 { Private declarations }
 public
 function GetServiceController: TServiceController; override;
 { Public declarations }
 end;
 
 var
 SvSvrMain: TSvSvrMain;
 
 implementation
 
 const
 CSRegServiceURL = 'SYSTEM\CurrentControlSet\Services\';
 CSRegDescription = 'Description';
 CSRegImagePath = 'ImagePath';
 CSServiceDescription = 'Services Sample.';
 
 {$R *.DFM}
 
 procedure ServiceController(CtrlCode: DWord); stdcall;
 begin
 SvSvrMain.Controller(CtrlCode);
 end;
 
 function TSvSvrMain.GetServiceController: TServiceController;
 begin
 Result := ServiceController;
 end;
 
 procedure TSvSvrMain.ServiceStart(Sender: TService;
 var Started: Boolean);
 begin
 Started := dmPublic.Start;
 end;
 
 procedure TSvSvrMain.ServiceStop(Sender: TService;
 var Stopped: Boolean);
 begin
 Stopped := dmPublic.Stop;
 end;
 
 procedure TSvSvrMain.ServiceBeforeInstall(Sender: TService);
 begin
 RegValueDelete(HKEY_LOCAL_MACHINE, CSRegServiceURL + Name, CSRegDescription);
 end;
 
 procedure TSvSvrMain.ServiceAfterInstall(Sender: TService);
 begin
 RegWriteString(HKEY_LOCAL_MACHINE, CSRegServiceURL + Name, CSRegDescription,
 CSServiceDescription);
 RegWriteString(HKEY_LOCAL_MACHINE, CSRegServiceURL + Name, CSRegImagePath,
 ParamStr(0) + ' -svc');
 end;
 
 end.
 这样,双击程序,则以普通程序方式运行,若用服务管理器来运行,则作为服务运行。
 例如公共模块:
 dmPublic,提供Start,Stop方法。
 
 在主窗体中,调用dmPublic.Start,dmPublic.Stop方法。
 同样在Service中,调用dmPublic.Start,dmPublic.Stop方法。
 
 
 
 |