首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Delphi Windows服务设计

Delphi Windows服务设计
EN

Stack Overflow用户
提问于 2012-05-10 15:24:23
回答 1查看 11.5K关注 0票数 21

Delphi Windows服务设计

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

现在我有一个应用程序(我将称之为UPDATEAPPLICATION),它为我们所有的其他应用程序提供更新。为了运行我们的任何应用程序,您首先必须运行这个UPDATEAPPLICATION程序,并将所需应用程序的参数传递给它。UPDATEAPPLICATION调用一个WebService,它返回关于所需应用程序是否有任何更新的XML信息。

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

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

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

我的设计我用的是DelphiXE2。我的设计将由三个部分组成,以形成一个单一的解决方案: Windows服务、用于与Windows服务交互的小型托盘应用程序以及将消息发送到Windows Service的重新设计的应用程序。

  1. My (我将称之为UPDATESERVICE)将作为Windows运行,并创建一个侦听请求的
  2. 服务器。TCP应用程序(我将称之为TRAYAPP)将使用UPDATESERVICE.
  3. My客户端配置/管理UPDATESERVICE.
  4. My USERAPPLICATION,启动时,将向UPDATESERVICE发送一条TCP消息,即“此应用程序”已启动。

UPDATESERVICE将监听消息。如果收到USERAPPLICATION已经启动的消息,它将调用web服务来查看是否有更新。如果存在,将通知用户关闭应用程序并允许UPDATESERVICE更新应用程序。UPDATESERVICE将下载适当的文件并更新应用程序。

现在我已经解释了我想要做什么的基本知识,我可以问我需要回答的具体问题。这些都与我应该如何构建我的Windows服务有关。我还计划在线程管理中使用OmniThread。

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

  1. 应该在它自己的线程上创建吗?如果TCP服务是它自己的线程,那么如何保持线程存活呢?否则,我可以启动TCP,但我不确定我将在TCP单元中使用哪些代码来保持线程running?
  2. What Windows事件应该创建TCP?OnExecute?OnStart?OnCreate?在我读过之后,还不清楚应该使用什么事件。
  3. 当UPDATESERVICE接收到要做某事的消息时,工作是在UPDATESERVICE线程内执行还是由主UPDATESERVICE生成的一个新线程?例如:如果UPDATESERVICE获得一条消息来检查使用HTTP进行更新的情况,则UPDATESERVICE线程应该生成一个新线程来完成此工作- matter?

  • ;或者,如果UPDATESERVICE线程向UPDATESERVICE发送一条消息以生成一个新线程来完成此工作

  1. 可以在Delphi中启动/停止/注册/注销窗口服务吗?

这都是我的问题。这可能没有正确或错误的答案,而仅仅是基于经验的偏好。如果您已经使用Delphi构建了服务,那么可能会有一些我认为有用的输入。如果您有一个比基本的“启动服务和睡眠”更健壮的项目,并且愿意共享它--即使我没有运行或只运行psuedo代码--我相信这将是非常宝贵的。谢谢你读了我冗长的问题。如果你能想出更好的方法来做这件事,请分享你的想法。我要补充的是,我们的几个应用程序可以由普通公众下载和运行,因此我无法完全控制预期的环境。如有任何建议/意见/帮助,将不胜感激。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2012-05-10 16:10:27

快速回答:

1和3)是的。根据经验,不要实现OnExecute服务事件。从OnStart服务事件派生自己的线程。当您收到OnStop服务事件时,可以终止该线程。

2)将线程保持如下状态(execute方法):

代码语言:javascript
复制
while not Terminated do
begin
  // do something
end;

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

5)是的,要意识到你需要更高的权利来做这件事。

在我的职业生涯中,我做了不少服务,到目前为止,我一直在服务应用程序中使用相同的框架:

代码语言:javascript
复制
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.
票数 31
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/10537267

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档