| 
 一、服务程序和桌面程序的区别 
 
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方法。 
  
 
 |