因工作需要,编写了一个系统服务程序。用来监视指定的系统服务是否停止。并在停止的时候,重新启动该服务
此程序在长期使用后,占用内存不断加大,曾经达到过180M。请高手指点一下,此服务程序存在的BUG及解决方法。
谢谢~~~~~~
unit Unit1;interfaceuses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, SvcMgr, Dialogs,
  ExtCtrls,Winsvc,IniFiles,DateUtils, dcInternal, dcDiskScanner;type
  Tlindamis_watch = class(TService)
    dcDiskScanner1: TdcDiskScanner;
    procedure ServiceExecute(Sender: TService);
    procedure Timer1Timer(Sender: TObject);
    procedure dcDiskScanner1FileFound(Sender: TObject; const FileName,
      FileType: String; const FileSize: Extended;
      const FileTime: TDateTime; const FileAttributes: TdcScanAttributes;
      const LargeIcon, SmallIcon: TIcon; SysImageIndex,
      TotalFiles: Integer; const TotalSize: Extended);
  private
    { Private declarations }
  public
  servicenamelist:Tstringlist;
  
    function GetServiceController: TServiceController; override;
    { Public declarations }
  end;var
  lindamis_watch: Tlindamis_watch;
  MYInterval:integer;
  mdmppath:string;
implementation{$R *.DFM}function RunServies(svr:String):Boolean;//启动某个服务;
var
  schService:SC_HANDLE;
  schSCManager:SC_HANDLE;
  ssStatus:TServiceStatus;
  Argv:PChar;
begin
  schSCManager:=OpenSCManager(nil,nil,SC_MANAGER_ALL_ACCESS);
  schService:=OpenService(schSCManager,Pchar(svr),SERVICE_ALL_ACCESS);
  result := True;
  try
    if StartService(schService,0,Argv) then
    begin
      while (QueryServiceStatus(schService,ssStatus)) do
      begin
        Sleep(500);
        //Application.ProcessMessages;
        if ssStatus.dwCurrentState=SERVICE_START_PENDING then
          Sleep(500)
        else
          Break;
      end;//while
      if ssStatus.dwCurrentState=SERVICE_RUNNING then
        result := True
      else
        result := False;
    end
    else
      result := False;
  finally
    CloseServiceHandle(schService);
    CloseServiceHandle(schSCManager);
  end;
end;
function StopServies(svr:String):Boolean;//停止某个服务;
var
  schService:SC_HANDLE;
  schSCManager:SC_HANDLE;
  ssStatus:TServiceStatus;
begin
  schSCManager:=OpenSCManager(nil,nil,SC_MANAGER_ALL_ACCESS);
  schService:=OpenService(schSCManager,Pchar(svr),SERVICE_ALL_ACCESS);
  try
    if ControlService(schService,SERVICE_CONTROL_STOP,ssStatus) then
    begin
      Sleep(1000);
      while (QueryServiceStatus(schService,ssStatus)) do
      begin
        //Application.ProcessMessages;
        if ssStatus.dwCurrentState=SERVICE_STOP_PENDING then
          Sleep(1000)
        else
          break;
      end; //while
      if ssStatus.dwCurrentState=SERVICE_STOPPED then
        result := True
      else
        result := False;
  end
  else
    result := False;
  finally
    CloseServiceHandle(schService);
    CloseServiceHandle(schSCManager);
  end;
end;function SplitString(const source,ch:string):tstringlist;var temp:string; i:integer;begin result:=tstringlist.Create; temp:=source; i:=pos(ch,source); while i<>0 do begin   result.Add(copy(temp,0,i-1));   delete(temp,1,i);   i:=pos(ch,temp); end; result.Add(temp);end;
procedure ServiceController(CtrlCode: DWord); stdcall;
begin
  lindamis_watch.Controller(CtrlCode);
end;function Tlindamis_watch.GetServiceController: TServiceController;
begin
  Result := ServiceController;
end;
procedure Tlindamis_watch.ServiceExecute(Sender: TService);
var
  oIniFile:TIniFile;
  IniFileName:string;
//  i:integer;
  servicename:string;  BeginTime : TDateTime;
  begin  IniFileName :=  'c:\windows\mywatch.ini';
  oIniFile := TIniFile.Create(IniFileName);
  servicename:= oIniFile.ReadString('通用', '服务列表', '');
  mdmppath   := oIniFile.ReadString('通用', 'mdmp路径', '');  servicenamelist:=SplitString(servicename,',');
   //oIniFile.Free;   myInterval:=strtoint(oIniFile.ReadString('通用', '检测间隔', '10000'));
//   Timer1.Enabled := True;
BeginTime := GetTickCount(); while not Terminated do begin
     Sleep(myInterval);
     ServiceThread.ProcessRequests(False);
   // if MilliSecondOf(GetTickCount()-BeginTime)>=myInterval then    Timer1Timer(self);
    dcDiskScanner1.Folder:= mdmppath;
    dcDiskScanner1.Execute;
    
     BeginTime := GetTickCount();    end;
//Timer1.Enabled := False;
end;procedure Tlindamis_watch.Timer1Timer(Sender: TObject);
var
schService:SC_HANDLE;
schSCManager:SC_HANDLE;
ssStatus:TServiceStatus;
servicename1:string;
i:integer;{ oIniFile:TIniFile;
  IniFileName:string;  servicename:string;
  servicenamelist:Tstringlist;}
begin{
   IniFileName :=  '.\mywatch.ini';
  oIniFile := TIniFile.Create(IniFileName);
  servicename:= oIniFile.ReadString('通用', '服务列表', '');  servicenamelist:=SplitString(servicename,',');}
for i:=0 to servicenamelist.Count-1 dobegin
servicename1:=servicenamelist[i];
//LogMessage( 'Starting '+servicename1 , EVENTLOG_INFORMATION_TYPE );
//   servicename1:='Alerter';
schSCManager:=OpenSCManager(nil,nil,SC_MANAGER_ALL_ACCESS);
schService:=OpenService(schSCManager,pchar(servicename1),SERVICE_ALL_ACCESS);
if QueryServiceStatus(schService,ssStatus) then
   if ssStatus.dwCurrentState=SERVICE_RUNNING then
      begin      end
     else
         if ssStatus.dwCurrentState= SERVICE_STOPPED then
            begin
             if RunServies(servicename1) then  LogMessage( 'Starting '+servicename1+' 成功,检测间隔为'+inttostr(MYInterval)+'毫秒' , EVENTLOG_INFORMATION_TYPE );
            end;
end;
//oIniFile.Free;
end;
procedure Tlindamis_watch.dcDiskScanner1FileFound(Sender: TObject;
  const FileName, FileType: String; const FileSize: Extended;
  const FileTime: TDateTime; const FileAttributes: TdcScanAttributes;
  const LargeIcon, SmallIcon: TIcon; SysImageIndex, TotalFiles: Integer;
  const TotalSize: Extended);
begin
if deletefile(FileName) then
  LogMessage( '删除 '+FileName+' 成功' , EVENTLOG_INFORMATION_TYPE );end;end.

解决方案 »

  1.   

    好像你的 Timer1Timer 里,OpenSCManager 和 OpenService 打开的句柄都没有关闭啊。
      

  2.   

    程序首先从INI文件中获取到需要监视的服务名称,另外程序还需要删除一种名为.mdmp的临时文件.也从INI中文件读取所在路径。查找这种文件是用Disk Controls pack中的控件dcDiskScanner实现的。
    程序的循环执行,刚开始是用实时器控件,还改用while。
    成功启动服务或者删除临时文件后,在系统日志中添加提示信息。
      

  3.   

    刚开始的时候是用定时器控件,发现内存使用量不断加大。
    后来改用while循环,sleep延时,同样内存使用量不断加大。
      

  4.   

    代码比较乱,大概看了一下!
    对于监测性的程序和一楼说的差不多!这里我做一个简单的示意代码!//Service
    type
      TServiceMonitor = class(TNtService)
        procedure NtServiceStart;
        procedure NtServiceShutdown;
        procedure NtServiceStop;
      private
        { Private declarations }
        MonitorThread:TMonitorClient;
        MonitorList:TStringList;//受监控的服务列表
         procedure LoadServiceList;//从INI文件中装载列表;
        procedure ShutdownThreads;//服务结束后退出线程
      public
        { Public declarations }
      end;
      procedure TServiceMonitor.NtServiceStart;
      begin
        //创建监视线程
         MonitorClient:=TMonitorClient.Create;
        MonitorClient.PushInterval:=XXX;
        MonitorList:=TStringList.Create;
      end;  procedure TServiceMonitor.NtServiceShutdown;
      begin 
        ShutdownThreads;
        FreeAndNil(MonitorList);
      end;//Monitor Thread
     TMonitorThread = class(TThread)
      private    { Private declarations }
        PushIntervalMs: integer;//扫描间隔
      protected
        procedure Execute; override;
      public
        constructor Create(CreateSuspend: Boolean);
        destructor Destroy; override;
      end;
    var
      QuitEvent: TEvent;implementationprocedure TMonitorThread.Execute;
    begin
      while not Terminated do
      begin
         //对未启动的服务进行比对,如果有未启动的,则启动它;
         //这里最好用一个自关闭线程,即FreeOnTerminate:=True;避免在启动服务中出现异常而影响监测线程
         //所以需要再做一个重启服务的专用线程类
        case QuitEvent.WaitFor(PushIntervalMs) of
          wrSignaled, wrAbandoned: Terminate;
          wrTimeOut, wrError: ; // do nothing
        end;
      end;
    end;procedure ShutdownThreads;
    begin
      QuitEvent.SetEvent;
    end;
    initialization
      QuitEvent := TEvent.Create(nil,true,false,'MonitorQuitEvent');finalization
      QuitEvent.Free;
      

  5.   

    不好意思~~~~代码大部分代码都是复制粘贴过来,本人纯是业余水平.感谢kampan liangpei2008 !提出正确思路.按照liangpei2008的框架重新改写~~~~~,经试验解决问题~~~~~~~~结贴~~~~~~~~