delphi 如何使用JCL启用Windows服务?

kg7wmglp  于 2023-10-18  发布在  Windows
关注(0)|答案(2)|浏览(119)

在JCL中有一个单元JclSvcCtrl,它有启动/停止服务的代码。我想在启动服务之前启用它,但我没有看到通过JCL实现这一点的方法。
我目前正在使用

procedure EnableService(ServiceName: string);
var
  SCManager: SC_HANDLE;
  Service: SC_HANDLE;
begin
  SCManager := OpenSCManager(nil, nil, SC_MANAGER_ALL_ACCESS);
  if (SCManager = 0) then
    RaiseLastOSError;
  try
    Service := OpenService(SCManager, PChar(ServiceName), SERVICE_ALL_ACCESS);
    if (Service = 0) then
      RaiseLastOSError;
    try
      if not ChangeServiceConfig(Service, SERVICE_NO_CHANGE, SERVICE_AUTO_START,
        SERVICE_NO_CHANGE, nil, nil, nil, nil, nil, nil, nil) then
        RaiseLastOSError;
    finally
      CloseServiceHandle(Service);
    end;
  finally
    CloseServiceHandle(SCManager);
  end;
end;

感谢ChatGPT。但我想知道是否有一个更简单的方法使用JCL?

ht4b089n

ht4b089n1#

JCL的JclSvcCtrl单元有一个TJclNtService类,其Commit()方法调用ChangeServiceConfig(),例如:

procedure EnableService(ServiceName: string);
var
  Scm: TJclSCManager;
  Svc: TJclNtService;
  EnumServiceStatus: TEnumServiceStatus;
begin
  Scm := TJclSCManager.Create;
  try
    Scm.Active := True;

    EnumServiceStatus.lpServiceName := PChar(ServiceName);
    EnumServiceStatus.lpDisplayName := '';

    Svc := TJclNtService.Create(Scm, EnumServiceStatus);
    try
      Svc.Refresh; // needed because TJclNtService doesn't support SERVICE_NO_CHANGE!
      Svc.StartType := sstAuto;
      Svc.Commit;
    finally
      Svc.Free;
    end;
  finally
    Scm.Free;
  end;
end;

在内部,Commit()调用QueryServiceConfig()以获取服务的当前基本配置,然后更新并提交其lpBinaryPathNamedwStartTypedwErrorControl值。因此,在调用Commit()之前,需要Refresh()来初始化TJclNtService.FileNameTJclNtService.ErrorControlType属性(除非您自己设置它们)。
但是,TJclNtService.Refresh()加载服务的整个配置(包括依赖项、加载组等)。Commit()也查询基本配置。所以,当你只想改变1个配置值时,这是相当多的开销。
在这种情况下,你最好继续直接调用ChangeServiceConfig(),这很简单。然而,我会建议一个小的调整-减少你正在请求的权限,不要请求你实际上不需要的权限,例如:

procedure EnableService(ServiceName: string);
var
  SCManager: SC_HANDLE;
  Service: SC_HANDLE;
begin
  SCManager := OpenSCManager(nil, nil, {SC_MANAGER_ALL_ACCESS}SC_MANAGER_CONNECT);
  if (SCManager = 0) then
    RaiseLastOSError;
  try
    Service := OpenService(SCManager, PChar(ServiceName), {SERVICE_ALL_ACCESS}SERVICE_CHANGE_CONFIG);
    if (Service = 0) then
      RaiseLastOSError;
    try
      if not ChangeServiceConfig(Service, SERVICE_NO_CHANGE, SERVICE_AUTO_START,
        SERVICE_NO_CHANGE, nil, nil, nil, nil, nil, nil, nil) then
        RaiseLastOSError;
    finally
      CloseServiceHandle(Service);
    end;
  finally
    CloseServiceHandle(SCManager);
  end;
end;
5t7ly7z5

5t7ly7z52#

如果您有权访问此注册表项,则可以更改服务的Start值:

HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Services

例如,自动启动为3,禁用为4,等等。

相关问题