DELPHI 编写服务程序的几点总结。

最近的项目又需要编写一些服务项应用了。由于很久没写代码了,有些东西忘了。不得不花点时间重新去找回。现把一些有用的贴出来,以便以后再用时方便。其中有些是网上找的。有些是自己心得。

 

TService


 

       属性介绍

           AllowPause   表明服务是否允许暂停。True则SCP(服务控制面板)上的暂停按钮时可用的,False则是不可用的
           AllowStop   表明服务是否允许停止。True则SCP(服务控制面板)上的停止按钮时可用的,False则是不可用的
           Dependecies   用于列出所有要依赖的服务
           DisplayName   显示在SCP上的服务名称
           ErrCode   指定一个错误代码。当遇到错误或提供状态信息时,就返回这个代码。如果ErrCode的值为0,则使用Win32ErrorCode属性。
           ErrorSeverity   表明如果启动服务时遇到错误,如何处理
           Interactive   表明是否可以显示一个对话框。只适用于Win32服务
           Name   服务的名称,即服务在SCM中的名称。如果要用SC.EXE或Net.exe来控制一个服务,必须指定服务的名称,而不是DisplayName指定的名称。
           Param   启动时的参数列表。用SC.exe来启动服务后,即可在SCP中指定参数,也可以从命令行中设置参数。
           ParamCount   传递个服务的参数个数
           Password   用于设置口令。只适合于不使用LoaclSystem账号的服务
           ServiceStartName   用于设置服务的账号名称,格式:域名/用户名
           ServiceThread   这是服务内部的线程,用于处理命令和请求
           ServiceType   服务的类型,可以设为:stWin32(Win32服务),stDevice(设备驱动程序)或stFileSystem(文件系统服务)
           Status     服务的当前状况(running,stopped,paused,stop   pending等)
           Terminated   表明内部的线程是否终止
           WaitHint   服务等待控制命令或状态请求的时间。如果在规定的时间内没有响应,则SCM认为服务出错
           Win32ErrCode   当发生错误或ErrCode属性的值为0时,包含一个系统定义的错误代码

      事件介绍:
            AfterInstall:安装服务之后调用的方法;
            AfterUninstall:服务卸载之后调用的方法;
            BeforeInstall:服务安装之前调用的方法;
            BeforeUninstall:服务卸载之前调用的方法;
            OnContinue:服务暂停继续调用的方法;
            OnExecute:执行服务开始调用的方法;
            OnPause:暂停服务调用的方法;
            OnShutDown:关闭时调用的方法;
            OnStart:启动服务调用的方法;
            OnStop:停止服务调用的方法;
            LogMessage()函数 用于发送一个消息到NT的事件日志种。
            ReportStatus()函数 用于发送服务的状态信息到SCM.

 

如何限制系统服务和桌面程序只运行一个
源文: http://hi.baidu.com/sqldebug/blog/item/58a764624a44d74eeaf8f863.html


View Code
在工程加入下列代码可以设置系统服务和桌面程序只运行一个。
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.


在系统服务和桌面程序之间共享内存
源文: http://hi.baidu.com/sqldebug/blog/item/58a764624a44d74eeaf8f863.html


 用于创建内核对象的函数几乎都有一个指向SECURITY_ATTRIBUTES结构的指针作为其参数,在使用CreateFileMapping函数的时候,通常只是为该参数传递NULL,这样就可以创建带有默认安全性的内核对象。  
    默认安全性意味着对象的管理小组的任何成员和对象的创建者都拥有对该对象的全部访问权,而其他所有人均无权访问该对象。可以指定一个ECURITY_ATTRIBUTES结构,对它进行初始化,并为该参数传递该结构的地址。  
   它包含的与安全性有关的成员实际上只有一个,即lpSecurityDescriptor。当你想要获得对相应的一个内核对象的访问权(而不是创建一个新对象)时,必须设定要对该对象执行什么操作。如果想要访问一个现有的文件映射内核对象,以便读取它的数据,那么调用OpenfileMapping函数:通过将FILE_MAP_READ作为第一个参数传递给OpenFileMapping,指明打算在获得对该文件映象的访问权后读取该文件,   该函数在返回一个有效的句柄值之前,首先  
   执行一次安全检查。如果(已登录用户)被允许访问现有的文件映射内核对象,就返回一个有效的句柄。但是,如果被拒绝访问该对象,将返回NULL。

 

 

系统服务端核心代码:
constructor TPublicVars.Create(ANew: Boolean);
var
  SecMem: SECURITY_ATTRIBUTES;
  aSD: SECURITY_DESCRIPTOR;
begin
  inherited Create;
  { 创建一个任何用户都可以访问的内核对象访问权 }
  InitializeSecurityDescriptor(@aSD, SECURITY_DESCRIPTOR_REVISION);
  SetSecurityDescriptorDacl(@aSD, True, 
nil, False);
  SecMem.nLength :
= SizeOf(SECURITY_ATTRIBUTES);
  SecMem.lpSecurityDescriptor :
= @aSD;
  SecMem.bInheritHandle :
= False;
  FMapFile :
= CreateFileMapping($FFFFFFFF, @SecMem, PAGE_READWRITE, 0, CSharedMemSize, CSharedMemName);
  FMapFile :
= OpenFileMapping(File_Map_All_Access, False, CSharedMemName);
  if (FMapFile = 0then
  begin
    
raise Exception.Create(SysErrorMessage(GetLastError));
    OutputDebugString(PChar(SysErrorMessage(GetLastError)));
  end
  else
  begin                                   // 成功
    FShareMem :
= MapViewOfFile(FMapFile, File_Map_All_Access, 00, CSharedMemSize);
    OutputDebugString(PChar(SysErrorMessage(GetLastError) 
+ ',Handle=' + IntToStr(Handle)));
  end;
end;

destructor TPublicVars.Destroy;
begin
  UnmapViewOfFile(FShareMem);
  CloseHandle(FMapFile);
  inherited;
end;

桌面程序核心源代码:
constructor TPublicVars.Create(ANew: Boolean);
var
  SecMem: SECURITY_ATTRIBUTES;
  aSD: SECURITY_DESCRIPTOR;
begin
  inherited Create;
  { 创建一个任何用户都可以访问的内核对象访问权 }
  InitializeSecurityDescriptor(@aSD, SECURITY_DESCRIPTOR_REVISION);
  SetSecurityDescriptorDacl(@aSD, True, 
nil, False);
  SecMem.nLength :
= SizeOf(SECURITY_ATTRIBUTES);
  SecMem.lpSecurityDescriptor :
= @aSD;
  SecMem.bInheritHandle :
= False;
  FMapFile :
= CreateFileMapping($FFFFFFFF, @SecMem, PAGE_READWRITE, 0, CSharedMemSize, CSharedMemName);
  FMapFile :
= OpenFileMapping(File_Map_All_Access, False, CSharedMemName);
  if (FMapFile = 0then
  begin
    
raise Exception.Create(SysErrorMessage(GetLastError));
    OutputDebugString(PChar(SysErrorMessage(GetLastError)));
  end
  else
  begin //成功
    FShareMem :
= MapViewOfFile(FMapFile, File_Map_All_Access, 00, CSharedMemSize);
    OutputDebugString(PChar(SysErrorMessage(GetLastError) 
+ ',Handle=' + IntToStr(Handle)));
  end;
end;

destructor TPublicVars.Destroy;
begin
  UnmapViewOfFile(FShareMem);
  CloseHandle(FMapFile);
inherited


在服务中使用COM组件


 

  在服务中调用COM组件不能像在桌面程序中直接创建,在每次创建之前先调用CoInitialize(nil),释放的时候调用CoUninitialize。例如:调用ADO组件

var
  Qry: TADOQuery;
begin
  CoInitialize(
nil);
  Qry :
= TADOQuery.Create(nil);
  
try
    ...
  
finally
    Qry.Free;
    CoUninitialize;
  
end;
end;


 

 

posted @ 2011-03-07 01:40  陆岛工作室  阅读(1316)  评论(0编辑  收藏  举报