2010-03-05 75 views

回答

48

完全可能。诀窍是编辑.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; 

上面的代码使用SvCom运行的服务,但可以使用标准的TService实现完全一样的效果。

我写了一篇关于多年前德尔福杂志的文章。你可以在这里阅读:Many Faces Of An Application

+0

是否可以创建一个'{$ DEFINE}'全局编译来识别它是在standlone还是windows服务模式下运行? – dipold 2015-09-15 18:24:44

+0

这个单元是什么'SvCom_NTService'? – 2018-01-18 23:01:45

+0

http://www.aldyn-software.com/svcom.html – gabr 2018-01-19 10:55:35

1

这是可能的,但在这种情况下,您不能使用正常的TServiceApplication和TService。你应该自己实现所有服务特定的代码。

我们有一个similat问题,并提出了两个框架应用程序:一个用于单独的沙EX和一个用于服务。现在我们可以创建一个嵌入到两个容器中的单个BPL/DLL。

如果你想花一些钱:你应该看看SvCOM,我认为他们有解决问题的办法。

9

这将是很难解释,但我会试试:)

我已经在我的项目一样,做到了(德尔福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. 
2

没有针对此问题的解决方案无需编写一行代码。这取决于你的应用程序,但通常它是可以实现的。试试这个:http://iain.cx/src/nssm。不要忘记启动您的应用程序所依赖的所有服务,然后才能将您的应用程序作为服务启动。谷歌围绕如何做到这一点的信息。

3

另一个差不多简单的选择可在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. 

虽然这个例子是现在已经相当过时,该技术是足够的,它简单仍然有效,即使使用Delphi XE2。有了这个,您的应用程序将继续作为非服务运行,直到您使用“/install”参数(在提升的命令提示符下)。之后它将作为服务运行,直到您使用“/卸载”参数(同样在提升的命令提示符下)。

相关问题