delphi - Delphi中同一个程序拥有多个NT服务

标签 delphi service

我正在寻找 Delphi 示例代码来开发可以多次安装的 Win32 Windows 服务(使用不同的名称)。 这个想法是为每个要安装的服务提供 1 个 exe 和 1 个注册表项以及 1 个子项。 我使用exe来安装/运行许多服务,每个服务都从他的注册表子项中获取他的参数。

有人有示例代码吗?

最佳答案

我们通过创建 TService 后代并添加“InstanceName”属性来完成此操作。这会在命令行上传递为类似于 ... instance="MyInstanceName"的内容,并在 SvcMgr.Application.Run 之前进行检查和设置(如果存在)。

例如 项目1.dpr:

program Project1;

uses
  SvcMgr,
  SysUtils,
  Unit1 in 'Unit1.pas' {Service1: TService};

{$R *.RES}

const
  INSTANCE_SWITCH = '-instance=';

function GetInstanceName: string;
var
  index: integer;
begin
  result := '';
  for index := 1 to ParamCount do
  begin
    if SameText(INSTANCE_SWITCH, Copy(ParamStr(index), 1, Length(INSTANCE_SWITCH))) then
    begin
      result := Copy(ParamStr(index), Length(INSTANCE_SWITCH) + 1, MaxInt);
      break;
    end;
  end;
  if (result <> '') and (result[1] = '"') then
    result := AnsiDequotedStr(result, '"');
end;

var
  inst: string;

begin
  Application.Initialize;
  Application.CreateForm(TService1, Service1);
  // Get the instance name
  inst := GetInstanceName;
  if (inst <> '') then
  begin
    Service1.InstanceName := inst;
  end;
  Application.Run;
end.

Unit1(TService 后代)

unit Unit1;

interface

uses
  Windows, SysUtils, Classes, SvcMgr, WinSvc;

type
  TService1 = class(TService)
    procedure ServiceAfterInstall(Sender: TService);
  private
    FInstanceName: string;
    procedure SetInstanceName(const Value: string);
    procedure ChangeServiceConfiguration;
  public
    function GetServiceController: TServiceController; override;
    property InstanceName: string read FInstanceName write SetInstanceName;
  end;

var
  Service1: TService1;

implementation

{$R *.DFM}

procedure ServiceController(CtrlCode: DWord); stdcall;
begin
  Service1.Controller(CtrlCode);
end;

procedure TService1.ChangeServiceConfiguration;
var
  mngr: Cardinal;
  svc: Cardinal;
  newpath: string;
begin
  // Open the service manager
  mngr := OpenSCManager(nil, nil, SC_MANAGER_ALL_ACCESS);
  if (mngr = 0) then
    RaiseLastOSError;
  try
    // Open the service
    svc := OpenService(mngr, PChar(Self.Name), SERVICE_CHANGE_CONFIG);
    if (svc = 0) then
      RaiseLastOSError;
    try
      // Change the service params
      newpath := ParamStr(0) + ' ' + Format('-instance="%s"', [FInstanceName]); // + any other cmd line params you fancy
      ChangeServiceConfig(svc, SERVICE_NO_CHANGE, //  dwServiceType
                               SERVICE_NO_CHANGE, //  dwStartType
                               SERVICE_NO_CHANGE, //  dwErrorControl
                               PChar(newpath),    //  <-- The only one we need to set/change
                               nil,               //  lpLoadOrderGroup
                               nil,               //  lpdwTagId
                               nil,               //  lpDependencies
                               nil,               //  lpServiceStartName
                               nil,               //  lpPassword
                               nil);              //  lpDisplayName
    finally
      CloseServiceHandle(svc);
    end;
  finally
    CloseServiceHandle(mngr);
  end;
end;

function TService1.GetServiceController: TServiceController;
begin
  Result := ServiceController;
end;

procedure TService1.ServiceAfterInstall(Sender: TService);
begin
  if (FInstanceName <> '') then
  begin
    ChangeServiceConfiguration;
  end;
end;

procedure TService1.SetInstanceName(const Value: string);
begin
  if (FInstanceName <> Value) then
  begin
    FInstanceName := Value;
    if (FInstanceName <> '') then
    begin
      Self.Name := 'Service1_' + FInstanceName;
      Self.DisplayName := Format('Service1 (%s)', [FInstanceName]);
    end;
  end;
end;

end.

用法:
Project1.exe/安装
Project1.exe/install -instance="MyInstanceName"
Project1.exe/卸载 [-instance="MyInstanceName]
它实际上不执行任何操作 - 由您来编写启动/停止服务器位等。

ChangeServiceConfiguration 调用用于更新服务管理器启动时调用的真实命令行。您可以只编辑注册表,但至少这是“正确的”API 方式。

这允许同时运行任意数量的服务实例,它们将在服务管理器中显示为“MyService”、“MyService (Inst1)”、“MyService (AnotherInstance)”等。

关于delphi - Delphi中同一个程序拥有多个NT服务,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2885359/

相关文章:

delphi - 如何获取Excel版本和宏安全级别

java - 如何向 Axis2 服务添加基本身份验证?

service - 横切需求/关注点在编程中意味着什么?

java - 使用委托(delegate)来分隔层

delphi - CharInSet 不适用于非英文字母?

windows - Windows 上的德尔福

windows - 远程 OpenSCManager 失败,访问被拒绝

authentication - Azure 移动服务/身份验证

delphi - 自动调整备忘录大小

delphi - 如何制作热键 Hook ? "Background hotkeys "