我是新手,想写一个查询Windows服务配置的小程序,现在遇到读内存非法的错误,不知道如何解决.程序如下:////查询所有预先定义的服务
procedure TControlWin.QueryAllService;
var
  ServiceNames:Array[0..2] of string;
  I:Integer;
  iniFileName:string;
  mService:TMyService;//自己定义的一种数据类型,保存服务名之类的参数
  ServiceConfig:PQueryServiceConfig;
begin
  ServiceNames[0] := 'MyServices1';
  ServiceNames[1] := 'MyServices2';
  ServiceNames[2] := 'MyServices3';
  ComboBox1.Items.Clear;
  for I := MyServiceList.Count - 1 downto 0 do
  begin
      TMyService(MyServiceList.Items[I]).Free;
  end;
  MyServiceList.Clear;
  for I := 0 to 2 do
  begin
  New( ServiceConfig);//给QUERY_SERVICE_CONFIG结构体指针分配内存
  if QueryMyServiceConfig(PAnsiChar(ServiceNames[I]),ServiceConfig) then
    begin
      mService := TMyService.Create;
      mService.ServiceName := ServiceNames[I];
      mService.DisplayName := StrPas(ServiceConfig.lpDisplayName);
      mService.BinaryPath := StrPas(ServiceConfig.lpBinaryPathName);
      mService.ServiceStatus := QueryMyServiceStatus(PAnsiChar(ServiceNames[I]));
      MyServiceList.Add(mService);
      ComboBox1.Items.Add(StrPas(ServiceConfig .lpDisplayName));
    end;
  Dispose(ServiceConfig);
  end;  if ComboBox1.Items.Count > 0 then
  begin
    ComboBox1.ItemIndex := 0;
    mService := TMyService(MyServiceList.Items[0]);
    iniFileName := ExtractFilePath(mService.BinaryPath)+mService.ServiceName+'.ini';
    if FileExists(iniFileName) then
    begin
    btnStart.Enabled := not mService.ServiceStatus;
    btnStop.Enabled := not btnStart.Enabled;
    end
    else
      begin
        btnStart.Enabled := False;
        btnStop.Enabled := False;
        btnConfigure.Enabled := True;
        ShowMessage('请先配置参数');
      end;
  end
  else
    begin
      btnStart.Enabled := False;
      btnStop.Enabled := False;
      btnConfigure.Enabled := False;
      ShowMessage('服务尚未安装');
    end;end;///查询某个服务的配置
function TControlWin.QueryMyServiceConfig(AServiceName: PAnsiChar; var AServiceConfig: PQueryServiceConfig):Boolean;
var
  hManager:SC_HANDLE;
  hService:SC_HANDLE;
  buffSize:Cardinal;
  Number:Cardinal;
begin
  Result:=False;
  hManager := OpenSCManager(nil,nil,SC_MANAGER_ALL_ACCESS);
  if hManager = NULL then
    Exit;  hService := OpenService(hManager, AServiceName, SERVICE_QUERY_CONFIG);
  if hService = 0 then
    begin
      if GetLastError = ERROR_SERVICE_DOES_NOT_EXIST then
      begin
      CloseServiceHandle(hManager);
      Exit;
      end;
    end;
  buffSize := 0;
  if not QueryServiceConfig(hService,nil,0,Number) then
    begin
      if GetLastError = ERROR_INSUFFICIENT_BUFFER then
      begin
        buffSize := Number;
      end;
    end;
  if not QueryServiceConfig(hService,AServiceConfig,buffSize,Number) then
    Result:=False
  else
    Result:=True;
  CloseServiceHandle(hService);
  CloseServiceHandle(hManager);
end;///查询某个服务的状态
function TControlWin.QueryMyServiceStatus(AServiceName: PAnsiChar):Boolean;
var
  hManager : SC_HANDLE;
  hService : SC_HANDLE;
  ServiceStatus : SERVICE_STATUS;
begin
Result := false;
  hManager := OpenSCManager(nil, nil, SC_MANAGER_ALL_ACCESS);  if hManager = 0 then
    begin
      Exit;
    end;  hService := OpenService(hManager, AServiceName, SERVICE_QUERY_STATUS);
  if hService = 0 then
    begin
      CloseServiceHandle(hManager);
      Exit;
    end;
  if not QueryServiceStatus(hService, ServiceStatus) then
    begin
      CloseServiceHandle(hService);
      CloseServiceHandle(hManager);
      Exit;
    end;
  case ServiceStatus.dwCurrentState of
    4 : Result := True;//服务正在运行
  end;
  CloseServiceHandle(hService);
  CloseServiceHandle(hManager);
  
end;问题描述:
我在窗体的FormCreate事件函数里调用了QueryAllService这个函数,程序正常,但是如果我在窗体里点击某个按钮,在这个按钮的Click事件处理函数里调用QueryAllService函数时,会出现一个读内存地址的错误,调用堆栈窗口显示是QueryAllService函数返回以后,显示"7c812a5b Kernel32.RaiseException + 0x52",看运行的顺序好像是在Graphics调用什么东西画窗体上的控件时出错,这里有个TResourceManager.AllocResource((no value)),估计是这里出问题了,因为程序调试的时候停在
TResourceManager.AllocResource函数的while (Result <> nil) and ((Result^.HashCode <> ResHash) or
      not CompareMem(@Result^.Data, @ResData, ResDataSize)) do
      Result := Result^.Next;
这里,而且此时Result^.Next中Next的地址刚好是报错的那个地址.不知道QueryMyServiceConfig在进行内存操作的时候跟窗体控件有什么关系啊,实在搞不懂,这个函数哪里有问题,高手指点一下

解决方案 »

  1.   

    查询Windows服务配置你可以到注册表里查看
    HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services
      

  2.   

    要实时查询服务的状态就只能通过SC Mananger了吧
      

  3.   

    恩,这个是我用的一个服务管理类,你参考一下吧unit ServiceManager;interfaceuses
      SysUtils, Windows, WinSvc;type  TServiceManager = class
      private
        { Private declarations }
        ServiceControlManager: SC_Handle;
        ServiceHandle: SC_Handle;
      protected
        function DoStartService(NumberOfArgument: DWORD; ServiceArgVectors: PChar): Boolean;
      public
        { Public declarations }
        function Connect(MachineName: PChar = nil; DatabaseName: PChar = nil;
          Access: DWORD = SC_MANAGER_ALL_ACCESS): Boolean;  // Access may be SC_MANAGER_ALL_ACCESS
        function OpenServiceConnection(ServiceName: PChar): Boolean;
        function StartService: Boolean; overload; // Simple start
        function StartService(NumberOfArgument: DWORD; ServiceArgVectors: PChar): Boolean;
          overload; // More complex start
        function StopService: Boolean;
        procedure PauseService;
        procedure ContinueService;
        procedure ShutdownService;
        procedure DisableService;
        function GetStatus: DWORD;
        function GetStatusCn: string;
        function ServiceRunning: Boolean;
        function ServiceStopped: Boolean;
      end;implementation{ TServiceManager }function TServiceManager.Connect(MachineName, DatabaseName: PChar;
      Access: DWORD): Boolean;
    begin
      { open a connection to the windows service manager }
      ServiceControlManager := OpenSCManager(MachineName, DatabaseName, Access);
      Result := (ServiceControlManager <> 0);
    end;function TServiceManager.OpenServiceConnection(ServiceName: PChar): Boolean;
    begin
      { open a connetcion to a specific service }
      ServiceHandle := OpenService(ServiceControlManager, ServiceName, SERVICE_ALL_ACCESS);
      Result := (ServiceHandle <> 0);
    end;procedure TServiceManager.PauseService;
    var
      ServiceStatus: TServiceStatus;
    begin
      { Pause the service: attention not supported by all services }
      ControlService(ServiceHandle, SERVICE_CONTROL_PAUSE, ServiceStatus);
    end;function TServiceManager.StopService: Boolean;
    var
      ServiceStatus: TServiceStatus;
    begin
      { Stop the service }
      Result := ControlService(ServiceHandle, SERVICE_CONTROL_STOP, ServiceStatus);
    end;procedure TServiceManager.ContinueService;
    var
      ServiceStatus: TServiceStatus;
    begin
      { Continue the service after a pause: attention not supported by all services }
      ControlService(ServiceHandle, SERVICE_CONTROL_CONTINUE, ServiceStatus);
    end;procedure TServiceManager.ShutdownService;
    var
      ServiceStatus: TServiceStatus;
    begin
      { Shut service down: attention not supported by all services }
      ControlService(ServiceHandle, SERVICE_CONTROL_SHUTDOWN, ServiceStatus);
    end;function TServiceManager.StartService: Boolean;
    begin
      Result := DoStartService(0, '');
    end;function TServiceManager.StartService(NumberOfArgument: DWORD;
      ServiceArgVectors: PChar): Boolean;
    begin
      Result := DoStartService(NumberOfArgument, ServiceArgVectors);
    end;function TServiceManager.GetStatus: DWORD;
    var
      ServiceStatus: TServiceStatus;
    begin
    { Returns the status of the service. Maybe you want to check this
      more than once, so just call this function again.
      Results may be: SERVICE_STOPPED
                      SERVICE_START_PENDING
                      SERVICE_STOP_PENDING
                      SERVICE_RUNNING
                      SERVICE_CONTINUE_PENDING
                      SERVICE_PAUSE_PENDING
                      SERVICE_PAUSED   }
      QueryServiceStatus(ServiceHandle, ServiceStatus);
      Result := ServiceStatus.dwCurrentState;
    end;procedure TServiceManager.DisableService;
    begin
      { Implementation is following... }
      DeleteService(ServiceHandle);
    end;function TServiceManager.ServiceRunning: Boolean;
    begin
      Result := (GetStatus = SERVICE_RUNNING);
    end;function TServiceManager.ServiceStopped: Boolean;
    begin
      Result := (GetStatus = SERVICE_STOPPED);
    end;function TServiceManager.DoStartService(NumberOfArgument: DWORD;
      ServiceArgVectors: PChar): Boolean;
    begin
      Result := WinSvc.StartService(ServiceHandle, NumberOfArgument, ServiceArgVectors);
    end;
    function TServiceManager.GetStatusCn: string;
    begin
      case GetStatus of
        SERVICE_STOPPED:          Result:='服务已停止';
        //SERVICE_START_PENDING:    Result:='正在启动服务';
        //SERVICE_STOP_PENDING:     Result:='正在停止服务';
        SERVICE_RUNNING:          Result:='服务正在运行';
        //SERVICE_CONTINUE_PENDING: Result:='正在重起服务';
        //SERVICE_PAUSE_PENDING:    Result:='正在停止服务';
        SERVICE_PAUSED:           Result:='服务已暂停';
      else
        Result:=( '状态未知' );
      end;
    end;end.