一个独立的 Delphi 应用程序,也可以作为 Windows 服务安装
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/2387383/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
A standalone Delphi application that can also be installed as windows service
提问by Vic
In Delphi you can create a standalone Windows VCL Forms application. You can also create a Windows service application.
在 Delphi 中,您可以创建一个独立的 Windows VCL Forms 应用程序。您还可以创建 Windows 服务应用程序。
Is it possible to combine the two in a single application that can run as a standalone application and can also be installed as a Windows service?
是否可以将两者结合在一个应用程序中,该应用程序可以作为独立应用程序运行,也可以作为 Windows 服务安装?
回答by gabr
Totally possible. The trick is to edit the .dpr to create main form when you want to run as an application and the service form when you want to run as a service. Like this:
完全有可能。诀窍是编辑 .dpr 以在您希望作为应用程序运行时创建主表单,并在您希望作为服务运行时创建服务表单。像这样:
if SvComFindCommand('config') then begin
//When run with the /config switch, display the configuration dialog.
Forms.Application.Initialize;
Forms.Application.CreateForm(TfrmConfig, frmConfig);
Forms.Application.Run;
end
else begin
SvCom_NTService.Application.Initialize;
SvCom_NTService.Application.CreateForm(TscmServiceSvc, scmServiceSvc);
SvCom_NTService.Application.Run;
end;
The code above uses SvCom to run the service but exactly the same effect could be achieved using the standard TService.
上面的代码使用 SvCom 来运行服务,但使用标准 TService 可以实现完全相同的效果。
I wrote an article about that for The Delphi Magazine many years ago. You can read it here: Many Faces Of An Application.
多年前,我为 Delphi 杂志写了一篇关于此的文章。您可以在此处阅读:应用程序的许多方面。
回答by SimaWB
It'll be hard to explain but I will try :)
很难解释,但我会尝试:)
I've done it in my project like that (Delphi 5):
我已经在我的项目中这样做了(Delphi 5):
program TestSvc;
uses SvcMgr,
SvcMain, //the unit for TTestService inherited from TService
...
;
var
IsDesktopMode : Boolean;
function IsServiceRunning : Boolean;
var
Svc: Integer;
SvcMgr: Integer;
ServSt : TServiceStatus;
begin
Result := False;
SvcMgr := OpenSCManager(nil, nil, SC_MANAGER_CONNECT);
if SvcMgr = 0 then Exit;
try
Svc := OpenService(SvcMgr, 'TestService', SERVICE_QUERY_STATUS);
if Svc = 0 then Exit;
try
if not QueryServiceStatus(Svc, ServSt) then Exit;
Result := (ServSt.dwCurrentState = SERVICE_RUNNING) or (ServSt.dwCurrentState = SERVICE_START_PENDING);
finally
CloseServiceHandle(Svc);
end;
finally
CloseServiceHandle(SvcMgr);
end;
end;
begin
if (Win32Platform <> VER_PLATFORM_WIN32_NT) or FindCmdLineSwitch('S', ['-', '/'], True) then
IsDesktopMode := True
else begin
IsDesktopMode := not FindCmdLineSwitch('INSTALL', ['-', '/'], True) and
not FindCmdLineSwitch('UNINSTALL', ['-', '/'], True) and
not IsServiceRunning;
end;
if IsDesktopMode then begin //desktop mode
Forms.Application.Initialize;
Forms.Application.Title := 'App. Title';
ShowTrayIcon(Forms.Application.Icon.Handle, NIM_ADD); // This function for create an icon to tray. You can create a popupmenu for the Icon.
while GetMessage(Msg, 0, 0, 0) do begin
TranslateMessage(Msg);
DispatchMessage(Msg);
end;
ShowTrayIcon(Forms.Application.Icon.Handle, NIM_DELETE); // for delete the tray Icon
end else begin // Service mode
SvcMgr.Application.Initialize;
SvcMgr.Application.CreateForm(TTestService, TestService);
SvcMgr.Application.Run;
end;
end.
回答by skamradt
Another almost simpler option is available at http://cc.embarcadero.com/item/19703, you just need to include a unit and change your DPR to something like:
另一个几乎更简单的选项可在http://cc.embarcadero.com/item/19703 获得,您只需要包含一个单位并将您的 DPR 更改为类似的内容:
begin
if CiaStartService('SERVICE NAME') then begin
CiaService.CreateForm(TMain, Main);
CiaService.Run;
Exit;
end;
Application.Initialize;
Application.Title := 'SERVICE NAME';
Application.CreateForm(TMain, Main);
Application.Run;
end.
While this example is now quite dated, the technique is simple enough that it still works, even with Delphi XE2. With this in place, your application will continue to operate as a non-service until you use the "/install" parameter (on an elevated command prompt). After which it will operate as a service until you use the "/uninstall" parameter (also on an elevated command prompt).
虽然这个例子现在已经过时了,但该技术很简单,即使在 Delphi XE2 中它仍然有效。有了这个,您的应用程序将继续作为非服务运行,直到您使用“ /install”参数(在提升的命令提示符下)。之后它将作为服务运行,直到您使用“ /uninstall”参数(也在提升的命令提示符下)。
回答by avra
There is a solution for this problem without writing a single line of code. It depends a little on your application, but generally it is achievable. Try this: http://iain.cx/src/nssm. Don't forget to start all services that you application depends on BEFORE you start your application as a service. Google around for info on how to do that.
这个问题有一个解决方案,无需编写一行代码。这在一定程度上取决于您的应用程序,但通常是可以实现的。试试这个:http: //iain.cx/src/nssm。在将应用程序作为服务启动之前,不要忘记启动应用程序依赖的所有服务。谷歌四处寻找有关如何做到这一点的信息。
回答by Ritsaert Hornstra
It is possible but in that case you cannot use the normal TServiceApplication and TService. You should implement all the service specific code yourself.
这是可能的,但在这种情况下,您不能使用普通的 TServiceApplication 和 TService。您应该自己实现所有特定于服务的代码。
We had a similat problem and made two frame applications: one for the sand alone exe and one for the service. Now we can create a single BPL/DLL that is embedded in both containers.
我们有一个similat问题,做了两个框架应用程序:一个用于沙子单独的exe,一个用于服务。现在我们可以创建一个嵌入在两个容器中的 BPL/DLL。
If you want to spend some money: you should look at SvCOM, I think they have a solution to the problem.
如果你想花一些钱:你应该看看SvCOM,我认为他们有解决问题的方法。