是否可以安装相同delphi服务应用程序的多个实例?

时间:2009-03-04 21:44:51

标签: delphi windows-services

我有一个用Delphi构建的服务应用程序,效果很好。它完全符合我的要求而且一切都很开心。一切都很好,直到我想在一台机器上运行该服务的两个(或更多)实例。由于服务名称被硬编码到程序中(通过服务的Name属性),我只能在任何给定的计算机上安装一次服务。如果我尝试在运行时修改Name属性,则除非将Name属性设置为在设计时设置的相同内容,否则服务不会响应。

我为此做了一个解决方法,我将所有代码都没有直接与服务控制管理器进行交互,这些代码被封装到单独的单元中。然后我为每个我想要服务的实例编写一个单独的Delphi项目,该项目只有足够的代码来启动自身并开始运行主代码。

在我看来,这种方法很难看,效率肯定很低。它适用于两个实例,但后来我们需要第三个和第四个......

有没有什么方法可以修改我的代码,这样我只有一个Delphi项目可以安装并运行自己作为多个服务实例,并带有一些简单的运行时输入(例如命令行标志)?

或许是一个更广泛的问题:是否有“正确的方法”来实现目标?

6 个答案:

答案 0 :(得分:14)

您还没有说明您在TService子类中尝试更改的内容。

您是否添加了“BeforeInstall”处理程序?

类似的东西:

procedure TServiceMain.ServiceLoadInfo(Sender : TObject);// new method, not an override
begin
  Name := ParamStr(2);
  DisplayName := ParamStr(3);
end;

procedure TServiceMain.ServiceBeforeInstall(Sender: TService);
begin
  ServiceLoadInfo(Self);
end;
procedure TServiceMain.ServiceCreate(Sender: TObject);
begin
  ServiceLoadInfo(Self);
end;

如果您经常这样做,请将TService子类化为构造函数。

你也应该在BeforeUninstall中做同样的事情 - 用同样的方法指向两个事件。

C:\>servicename /install MyService "My Service Description"

答案 1 :(得分:3)

您可以在内部创建多个线程的服务,每个线程都像它自己的服务版本/副本一样。您可以使用服务控制器API IIRC来控制它。

答案 2 :(得分:2)

是的,可以安装同一服务的多个实例,您只需要在安装时动态更改名称(而不是运行时),但这并不是理想的。 (代码项目http://www.codeproject.com/KB/dotnet/MultipleInstNetWinService.aspx上有一些示例代码)

然而,我会倾向于重新思考你的方法,服务流程本身就是单身,如果你需要运行一个流程的多个实例,也许你的服务应该只控制和管理多个流程而不是流程

答案 3 :(得分:0)

将所有代码包装到一个继承自TThread的类中。

当您的服务启动时,它将从设置文件或注册表中读取一个数字,并创建该类的许多实例。

每个实例独立运行。

要更改可以关闭服务的正在运行的实例数,请编辑设置(在文件或注册表中)并重新启动服务。

答案 4 :(得分:0)

上面接受的答案非常有用。

我使用的代码:

procedure TService1.ServiceAfterInstall(Sender: TService);
begin
//http://stackoverflow.com/questions/612587/is-it-possible-to-install-multiple-instances-of-the-same-delphi-service-applicati
//http://www.c-sharpcorner.com/UploadFile/timosten/DynamicServiceInCSharp11262005062503AM/DynamicServiceInCSharp.aspx?ArticleID=4d5020e4-7317-425c-ab29-5bf37a1db421
//http://support.microsoft.com/kb/137890
  SaveRegSetting('\SYSTEM\CurrentControlSet\Services\' + Name, 'ImagePath', ParamStr(0) + ' --name=' + Name, HKEY_LOCAL_MACHINE)
end;

procedure TService1.ServiceCreate(Sender: TObject);
begin
  Name := Trim(FCommandLineOptions.Values['name']);
  DisplayName := Name;
end;

SaveRegSetting是我自己的过程,FCommandLineOptions是一个标记命令行参数的对象。

答案 5 :(得分:0)

出于黑客入侵注册表的考虑,我建议您使用以下指南并使用Windows服务控制器(sc.exe)命令行界面:

When creating a service with sc.exe how to pass in context parameters?

(编辑:请按照建议的方式使用代码来获取Name和DisplayName属性,只是不要使用服务可执行文件的/ install开关安装服务。)