delphiwindows服务设计

delphiwindows服务设计,windows,delphi,service,tcp,Windows,Delphi,Service,Tcp,delphiwindows服务设计 我从未创建过windows服务,但一直在阅读我找到的所有内容。我遇到的所有文章或示例在实现方面都非常基本,并且范围有限。还没有看到任何超出此范围或解决特定场景的内容。所以,我有可能找到的所有理论,现在我准备投入这个项目。我喜欢规划我的想法,并从人们的想法中得到一些反馈。我将描述我需要从应用程序中得到什么,以及我打算如何构建它。我非常感谢任何有构建windows服务经验的人的评论,以及他们愿意分享的任何建议 [场景] 现在我有一个应用程序(我称之为UPDATEA

delphiwindows服务设计

我从未创建过windows服务,但一直在阅读我找到的所有内容。我遇到的所有文章或示例在实现方面都非常基本,并且范围有限。还没有看到任何超出此范围或解决特定场景的内容。所以,我有可能找到的所有理论,现在我准备投入这个项目。我喜欢规划我的想法,并从人们的想法中得到一些反馈。我将描述我需要从应用程序中得到什么,以及我打算如何构建它。我非常感谢任何有构建windows服务经验的人的评论,以及他们愿意分享的任何建议

[场景] 现在我有一个应用程序(我称之为UPDATEAPPLICATION),它为所有其他应用程序提供更新。为了运行我们的任何应用程序,您首先必须运行此UPDATEAPPLICATION程序,并向其传递所需应用程序的参数。UPDATEAPPLICATION调用一个Web服务,该服务返回有关所需应用程序是否有任何更新的XML信息

如果有更新,UPDATEAPPLICATION将以EXE或ZIP格式下载更新,并替换相应的文件以更新目标应用程序。之后,UPDATEAPPLICATION执行ShellExecute以启动所需的应用程序,然后UPDATEAPPLICATION关闭

这是一个相当基本的过程,多年来一直运作良好。UPDATEAPPLICATION程序是一个Delphi应用程序,我们的其他应用程序是混合的:Delphi、VB6、MS Access、.NET

[问题] 随着Vista和Windows7的出现,安全性发生了巨大的变化。由于UPDATEAPPLICATION的性质,UAC不允许应用程序在没有管理员访问或UAC完全关闭的情况下运行。我们正在将许多应用程序升级到.NET,在此过程中,我希望这些应用程序以及UPDATEAPPLICATION都符合UAC。根据我的研究,实现这一点的唯一方法是将UPDATEAPPLICATION创建为Windows服务。因此,本质上,我需要将UPDATEAPPLICATION的功能复制到Windows服务体系结构中

[我的设计] 我用的是DelphiXE2。我的设计将由3个部分组成一个单一的解决方案:一个Windows服务,一个与Windows服务交互的小托盘应用程序,以及我重新设计的将向Windows服务发送消息的应用程序

  • 我的Windows服务(我称之为UPDATESERVICE)将作为Windows服务运行,并创建一个TCP服务器来侦听请求
  • 托盘应用程序(我将称之为TRAYAPP)将使用TCP客户端来配置/管理UPDATESERVICE
  • 启动时,我的用户应用程序将向UPDATESERVICE发送一条TCP消息,表示“此应用程序”已启动
  • [更新服务] 将侦听消息。如果它收到一条消息,表示用户应用程序已启动,它将调用web服务以查看是否有更新。如果存在,将通知用户关闭应用程序并允许UPDATESERVICE更新应用程序。UPDATESERVICE将下载适当的文件并更新应用程序

    既然我已经解释了我要做的事情的基本原理,我可以问我需要回答的具体问题。这些都与我应该如何构建Windows服务有关。我还计划使用OmniThread进行线程管理

    当我的服务启动时,我需要创建TCP服务器

  • TCP服务应该在它自己的线程上创建吗
  • 如果TCP服务是它自己的线程,那么如何使线程保持活动状态?否则,我可以启动TCP服务,但我不确定在TCP服务单元中使用什么代码来保持线程运行
  • 什么Windows服务事件应该创建TCP服务?真的吗?开始?一次创建?毕竟我已经读过了,还不清楚应该使用什么事件
  • 当TCP服务接收到要执行某项操作的消息时,工作应该在TCP服务线程内执行,还是在主UPDATESERVICE派生的新线程内执行?例如:
    • 如果TCP服务收到一条消息,要使用HTTP检查更新,TCP服务线程是否应该生成一个新线程来执行此工作
    • 或者,TCP服务线程是否应该向UPDATESERVICE发送一条消息以生成一个新线程来执行此工作
    • 这有关系吗
  • 是否可以在Delphi代码中启动/停止/注册/注销windows服务
  • 这是我所有的问题。对此可能没有正确/错误的答案,而只是基于经验的偏好。如果您已经使用Delphi构建了服务,您可能会有一些我认为有用的输入。如果您有一个比基本的“启动服务并睡眠”更健壮的项目,并且愿意共享它——即使我不运行或只是psuedo代码——我相信这将是非常宝贵的。谢谢你阅读我冗长的问题。如果你能想出更好的方法,请分享你的想法。我要补充的是,我们的几个应用程序可以由公众下载和运行,因此我无法完全控制预期的环境。如有任何建议/意见/帮助,将不胜感激

    快速回答:

    是的。根据经验,不要实现OneExecute服务事件。从OnStart服务事件生成您自己的线程。当您收到OnStop服务事件时,线程可以终止

    2) 您可以这样保持线程的活动状态(执行方法):

    4) 通常情况下,每个客户端连接都将位于其自己的线程上。(即TCP服务器为每个客户端生成一个新线程)。使用众所周知的堆栈,如Indy或ICS。关于HTTP更新,您可以在派生的客户端连接线程中执行此操作

    5) 是的,请注意,您需要提升权限才能执行此操作

    在我的职业生涯中,我做了很多服务,我总是使用
    while not Terminated do
    begin
      // do something
    end;
    
    unit u_svc_main;
    
    interface
    
    uses
      // Own units
      u_globals, u_eventlog, u_MyThread, 
      // Third party units
      // Delphi units
      Windows, Messages, Registry, SysUtils, Classes, SvcMgr;
    
    type
      TMyService = class(TService)
        procedure ServiceCreate(Sender: TObject);
        procedure ServiceAfterUninstall(Sender: TService);
        procedure ServiceAfterInstall(Sender: TService);
        procedure ServiceShutdown(Sender: TService);
        procedure ServiceStop(Sender: TService; var Stopped: Boolean);
        procedure ServiceStart(Sender: TService; var Started: Boolean);
      private
        { Private declarations }
        MyThread : TMyThread;
      public
        { Public declarations }
        function GetServiceController: TServiceController; override;
      end;
    
    var MyService : TMyService;
    
    implementation
    
    {$R *.DFM}
    
    procedure ServiceController(CtrlCode: DWord); stdcall;
    begin
      MyService.Controller(CtrlCode);
    end;
    
    function TMyService.GetServiceController: TServiceController;
    begin
      Result := ServiceController;
    end;
    
    procedure TMyService.ServiceCreate(Sender: TObject);
    begin
      DisplayName := 'myservice';
    end;
    
    procedure TMyService.ServiceAfterInstall(Sender: TService);
    var
      Reg        : TRegistry;
      ImagePath  : string;
    begin
      // create needed registry entries after service installation
      Reg := TRegistry.Create;
      try
        Reg.RootKey := HKEY_LOCAL_MACHINE;
        // set service description
        if Reg.OpenKey(STR_REGKEY_SVC,False) then
        begin
          ImagePath := Reg.ReadString(STR_REGVAL_IMAGEPATH);
          Reg.WriteString(STR_REGVAL_DESCRIPTION, STR_INFO_SVC_DESC);
          Reg.CloseKey;
        end;
        // set message resource for eventlog
        if Reg.OpenKey(STR_REGKEY_EVENTMSG, True) then
        begin
          Reg.WriteString(STR_REGVAL_EVENTMESSAGEFILE, ImagePath);
          Reg.WriteInteger(STR_REGVAL_TYPESSUPPORTED, 7);
          Reg.CloseKey;
        end;
        // set installdir
        if ImagePath <> '' then
          if Reg.OpenKey(STR_REGKEY_FULL,True) then
          begin
            Reg.WriteString(STR_REGVAL_INSTALLDIR, ExtractFilePath(ImagePath));
            Reg.CloseKey;
          end;
      finally
        FreeAndNil(Reg);
      end;
    end;
    
    procedure TMyService.ServiceAfterUninstall(Sender: TService);
    var
      Reg : TRegistry;
    begin
      Reg := TRegistry.Create;
      try
        // delete self created registry keys
        Reg.RootKey := HKEY_LOCAL_MACHINE;
        Reg.DeleteKey(STR_REGKEY_EVENTMSG);
      finally
        FreeAndNil(Reg);
      end;
    end;
    
    procedure TMyService.ServiceShutdown(Sender: TService);
    var
      Stopped : boolean;
    begin
      // is called when windows shuts down
      ServiceStop(Self, Stopped);
    end;
    
    procedure TMyService.ServiceStart(Sender: TService; var Started: Boolean);
    begin
      Started := False;
      try
        MyThread := TMyThread.Create;
        MyThread.Resume;
        NTEventLog.Add(Eventlog_Success, STR_INFO_SVC_STARTED);
        Started := True;
      except
        on E : Exception do
        begin
          // add event in eventlog with reason why the service couldn't start
          NTEventLog.Add(Eventlog_Error_Type, Format(STR_INFO_SVC_STARTFAIL, [E.Message]));
        end;
      end;
    end;
    
    procedure TMyService.ServiceStop(Sender: TService; var Stopped: Boolean);
    begin
      try
        Stopped := True; // always stop service, even if we had exceptions, this is to prevent "stuck" service (must reboot then)
        MyThread.Terminate;
        // give MyThread 60 seconds to terminate
        if WaitForSingleObject(MyThread.ThreadEvent, 60000) = WAIT_OBJECT_0 then
        begin
          FreeAndNil(MyThread);
          NTEventLog.Add(Eventlog_Success,STR_INFO_SVC_STOPPED);
        end;
      except
        on E : Exception do
        begin
          // add event in eventlog with reason why the service couldn't stop
          NTEventLog.Add(Eventlog_Error_Type, Format(STR_INFO_SVC_STOPFAIL, [E.Message]));
        end;
      end;
    end;
    
    end.