打开APP
userphoto
未登录

开通VIP,畅享免费电子书等14项超值服

开通VIP
Delphi 在Windows 11中开发Windows服务:最佳实践和工具_delphi 服务程序调试_sensor

当你开发Windows软件时,你会遇到某些种类的应用程序需要24小时运行,或者,事实上,在计算机运行时持续不断地运行。通常情况下,这些计算机是网络服务器或台式机上的监控应用程序。在这些情况下,你可能会考虑创建一个控制台应用程序,它要么有最小的交互量,要么完全无声,但有比这更好的解决方案。

简单的控制台或最小化的普通GUI应用程序可能面临Windows会话终止、重启和用户权限等问题。解决这个问题的方法是开发Windows服务。在本教程中,我们将深入研究使用Delphi构建Windows服务。在这之后,你可以把它作为你的Windows服务的模板。

目录

为什么我需要创建一个Windows服务?

开发Windows服务的先决条件是什么?

Windows服务应用程序是如何工作的?

你什么时候需要编写Windows服务?

如何在Delphi中创建一个Windows服务项目?

如何用Delphi实现一个Windows服务应用?

我们如何实现Windows服务应用功能?

使用Windows服务管理器测试服务

调试服务应用程序


为什么我需要创建一个Windows服务?

创建长期运行的服务有许多原因,如::

  • 处理CPU密集型数据。
  • 在后台排队的工作项目。
  • 在时间表上执行基于时间的操作
  • 对 "助手 "或实用程序功能进行不引人注目的操作

后台服务处理通常不涉及用户界面(UI),但可以围绕它们建立UI

开发Windows服务的先决条件是什么?

在开始潜心研究服务应用开发之前,我建议你看看最新版本的Delphi IDE。有了大量的增强功能和新特性,开发过程会更加顺利。此外,你可以免费使用Delphi社区版,熟悉Delphi编程语言和它的语法。

Windows服务应用程序是如何工作的?

服务应用程序从客户端应用程序接收请求,处理这些请求,并将信息返回给客户端应用程序。一个Web、FTP或电子邮件服务器就是一个服务应用程序的例子。

一个Windows服务应用程序是一个可以运行而不需要用户登录的Windows应用程序。Windows服务应用程序很少与桌面互动。在本教程中,我们将用Delphi创建一个Windows服务应用程序。

当一个服务程序运行时,它可以被设置为使用一套默认的用户权限,既可以作为一个虚拟的 "服务用户",也可以作为一个实际的具有访问系统权限的普通用户。重要的是,这些用户权限会影响到你的服务应用程序有权访问的文件夹,以及任何 "映射 "的网络文件夹--如果有人创建了一个映射,比如一个指向网络文件夹的 "Z: "驱动器很可能无法使用。在可能的情况下,你应该总是使用完整的UNC路径名称--或者使用Windows系统调用或Delphi的运行时TPath类型函数来获得特殊文件夹的正确位置,如%APPDATA%文件夹的位置和 "我的文档 "类型的虚拟路径。

Windows服务应用程序可以提供很多功能。当你启动服务实用工具时,请看列表。这些服务可以成为你使用的主要GUI应用程序的核心。

你什么时候需要编写Windows服务?

前段时间,我需要一个系统监控工具来监控我们文件服务器上的可用磁盘空间。我写了一个工具,每分钟检查一次,然后把这些信息写到一个日志文件中。然而,它需要一个用户登录,而当用户退出时,我的应用程序就关闭了。解决办法是将该程序重新创建为一个Windows服务,然后在计算机开机时一直运行,即使用户没有登录。

虽然RAD Studio与Delphi或C++ Builder对典型的面向用户的交互式应用程序进行了优化,但它更有能力轻松创建服务应用程序。

如何在Delphi中创建一个Windows服务项目?

要在Delphi中创建一个新的项目,你需要在你的计算机上安装Delphi开发环境。一旦你安装并运行了Delphi,你就可以开始创建一个新的项目。

要在RAD Studio中用Delphi创建一个新的Windows服务项目,采取以下步骤:

  1. 点击文件菜单,选择新建->其他。这将弹出 "新建项目 "对话框。
  2. 在对话框的左侧,选择Delphi,然后从Windows类别中选择Windows服务项目类型。
  3. 点击 "确定 "来创建新项目。

 请注意,对于那些使用C++ Builder的人来说,这个过程是类似的。

一旦新项目被创建,你将需要设置项目属性和选项。要做到这一点,在 "项目管理器 "窗口中右击项目名称,选择 "选项"。这将弹出 "项目选项 "对话框。在这个对话框中,你可以为你的项目设置各种选项,如目标平台、输出目录和编译器选项。在继续开发你的服务之前,请确保根据你的项目要求设置这些选项。

如何用Delphi实现一个Windows服务应用?

在Delphi中创建一个新的Windows服务项目并设置项目属性和选项后,下一步是实现服务本身。这涉及到向主要的服务单元添加代码,该单元通常被默认为 "Unit1.pas"。

要开始,在 "项目管理器 "窗口中双击 "Unit1.pas "文件,在代码编辑器中打开它。这将显示该单元的代码文件,它包含了Delphi服务应用程序的骨架代码。

要在单元中添加自己的代码,你需要通过处理各种服务事件来定义服务的行为。这些事件包括启动、停止和暂停事件,它们分别在服务启动、停止或暂停时被触发。

为了处理这些事件,你可以使用Delphi内置的服务组件,"TService "类。这个组件提供了各种方法和属性,你可以用它们来控制服务的行为,比如 "开始 "和 "停止 "方法。

例如,你可以使用 "OnStart "事件处理程序来定义服务启动时应该执行的代码。要做到这一点,你可以在 "Unit1.pas "文件中添加以下代码:

  1. procedure TService1.ServiceStart(Sender: TService; var Started: Boolean);
  2. begin
  3. // code you want to execute when the service starts
  4. // such as making a log entry
  5. end;

除了启动和停止事件外,你可能还需要处理暂停事件,它是在服务暂停时触发的。要做到这一点,你可以使用 "OnPause "事件处理程序,它类似于 "OnStart "和 "OnStop "事件处理程序。

例如,你可以在 "Unit1.pas "文件中添加以下代码来处理暂停事件:

  1. procedure TService1.ServicePause(Sender: TService; var Paused: Boolean);
  2. begin
  3. // Add your code here for things to happen when the user
  4. // chooses "pause" from the service menu or uses the service control
  5. // commands to pause your service.
  6. // This is NOT the same as the service being stopped!
  7. end;

在每一个事件处理程序中,你可以添加你自己的代码来定义当各自事件被触发时服务的行为。例如,你可以使用 "TService "组件的 "Start "和 "Stop "方法来启动或停止一个定时器或一个线程,或者你可以使用 "Pause "方法来暂停一个任务的执行。

一旦你将代码添加到主服务单元并处理了服务的事件,你就可以使用Delphi调试器和Windows服务管理器继续调试和测试服务。

我们如何实现Windows服务应用功能?

在单元的Uses子句中添加Vcl.SvcMgr单元。

通过修改TForm类的声明,将主窗体的祖先改为TService,如下

  1. type
  2. TService1 = class(TService)

这里有完整的源代码:

  1. unit ServiceUnit;
  2. interface
  3. uses
  4. Winapi.Windows
  5. , Winapi.Messages
  6. , System.SysUtils
  7. , System.Classes
  8. , Vcl.Graphics
  9. , Vcl.Controls
  10. , Vcl.SvcMgr
  11. , Vcl.Dialogs
  12. , BackgroundThreadUnit
  13. , System.Win.Registry;
  14. type
  15. TService1 = class(TService)
  16. procedure ServiceExecute(Sender: TService);
  17. procedure ServiceStart(Sender: TService; var Started: Boolean);
  18. procedure ServiceStop(Sender: TService; var Stopped: Boolean);
  19. procedure ServicePause(Sender: TService; var Paused: Boolean);
  20. procedure ServiceContinue(Sender: TService; var Continued: Boolean);
  21. procedure ServiceAfterInstall(Sender: TService);
  22. private
  23. FBackgroundThread: TBackgroundThread;
  24. { Private declarations }
  25. public
  26. function GetServiceController: TServiceController; override;
  27. { Public declarations }
  28. end;
  29. {$R *.dfm}
  30. var
  31. MyService: TService1;
  32. implementation
  33. procedure ServiceController(CtrlCode: DWord); stdcall;
  34. begin
  35. MyService.Controller(CtrlCode);
  36. end;
  37. procedure TService1.ServiceExecute(Sender: TService);
  38. begin
  39. while not Terminated do
  40. begin
  41. ServiceThread.ProcessRequests(false);
  42. TThread.Sleep(1000);
  43. end;
  44. end;
  45. function TService1.GetServiceController: TServiceController;
  46. begin
  47. Result := ServiceController;
  48. end;
  49. procedure TService1.ServiceContinue(Sender: TService;
  50. var Continued: Boolean);
  51. begin
  52. FBackgroundThread.Continue;
  53. Continued := True;
  54. end;
  55. procedure TService1.ServiceAfterInstall(Sender: TService);
  56. var
  57. Reg: TRegistry;
  58. begin
  59. Reg := TRegistry.Create(KEY_READ or KEY_WRITE);
  60. try
  61. Reg.RootKey := HKEY_LOCAL_MACHINE;
  62. if Reg.OpenKey('SYSTEMCurrentControlSetServices' + name, false) then
  63. begin
  64. Reg.WriteString('Description', 'Blogs.Embarcadero.com');
  65. Reg.CloseKey;
  66. end;
  67. finally
  68. Reg.Free;
  69. end;
  70. end;
  71. procedure TService1.ServicePause(Sender: TService; var Paused: Boolean);
  72. begin
  73. FBackgroundThread.Pause;
  74. Paused := True;
  75. end;
  76. procedure TService1.ServiceStop(Sender: TService; var Stopped: Boolean);
  77. begin
  78. FBackgroundThread.Terminate;
  79. FBackgroundThread.WaitFor;
  80. FreeAndNil(FBackgroundThread);
  81. Stopped := True;
  82. end;
  83. procedure TService1.ServiceStart(Sender: TService; var Started: Boolean);
  84. begin
  85. FBackgroundThread := TBackgroundThread.Create(True);
  86. FBackgroundThread.Start;
  87. Started := True;
  88. end;
  89. end.

这里的后台线程代码如下:

  1. unit BackgroundThreadUnit;
  2. interface
  3. uses
  4. System.Classes;
  5. type
  6. TBackgroundThread = class(TThread)
  7. private
  8. FPaused: Boolean;
  9. // FTerminated: Boolean;
  10. // FOnTerminate: TNotifyEvent;
  11. protected
  12. procedure Execute; override;
  13. public
  14. procedure Pause;
  15. procedure Continue;
  16. // procedure Terminate;
  17. // property OnTerminate: TNotifyEvent read FOnTerminate write FOnTerminate;
  18. end;
  19. implementation
  20. uses
  21. System.SysUtils, System.IOUtils;
  22. procedure TBackgroundThread.Continue;
  23. begin
  24. FPaused := False;
  25. end;
  26. // process something here
  27. procedure TBackgroundThread.Execute;
  28. var
  29. LogFile: TextFile;
  30. begin
  31. try
  32. FPaused := False;
  33. AssignFile(LogFile, 'C:TempLogs.log');
  34. Rewrite(LogFile);
  35. while not Terminated do
  36. begin
  37. if not FPaused then
  38. begin
  39. WriteLn(LogFile, 'Logs From Background Thread: ' + DateTimeToStr(Now));
  40. end;
  41. TThread.Sleep(1000);
  42. end;
  43. finally
  44. CloseFile(LogFile);
  45. end;
  46. end;
  47. procedure TBackgroundThread.Pause;
  48. begin
  49. FPaused := True;
  50. end;
  51. end.

现在你可以建立服务了。在项目窗口,你可以打开上下文菜单,像这样建立服务:

Delphi构建Windows服务

使用Windows服务管理器测试服务

你可以使用Windows服务管理器来测试服务。这个工具允许你启动、停止、暂停和恢复一个服务,并查看其状态和可能遇到的任何错误。

要安装该服务,你应该遵循以下步骤:

  • 进入文件夹,在终端打开(可执行文件应配置为以管理员权限运行)
  • 用"/install "命令输入服务名称

进入该文件夹并在终端打开

使用终端安装Windows服务

一旦服务被安装,你可以使用Windows服务管理器启动、停止、暂停或恢复该服务。要做到这一点,在Windows控制面板的管理工具文件夹中打开服务应用程序。在服务列表中找到该服务,右键单击它,并从上下文菜单中选择所需的操作。

在这里你可以启动、停止和暂停服务

几秒钟后,从服务管理器中停止该服务并检查日志文件。

附录:

调试服务应用程序

你可以在服务应用程序已经运行的情况下,通过附加到服务应用程序进程来调试服务应用程序(也就是说,先启动服务,然后附加到调试器上)。要附加到服务应用程序进程,选择 Run > Attach To Process,并在出现的对话框中选择服务应用程序。

在某些情况下,由于权限不足,这种方法可能会失败。如果发生这种情况,你可以使用服务控制管理器来使你的服务能够与调试器一起工作:

要进行调试:

  1. 首先在以下注册表位置创建一个名为图像文件执行选项的键: HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion
  2. 创建一个与你的服务同名的子键(例如,MYSERV.EXE)。在这个子键上,添加一个REG_SZ类型的值,名为Debugger。使用bds.exe的完整路径作为字符串值。
  3. 在服务控制面板小程序中,选择你的服务,点击启动并勾选允许服务与桌面互动。

对于Windows NT:

在Windows NT系统上,你可以使用另一种方法来调试服务应用程序。然而,这种方法可能很棘手,因为它需要很短的时间间隔:

  1. 首先,在调试器中启动该应用程序。等待几秒钟,直到它完成加载。
  2. 从控制面板或命令行中快速启动服务:启动MyServ

你必须快速启动服务(在应用程序启动后15-30秒内),因为如果没有启动服务,应用程序将终止。

How to Delete a Windows Service?

Open PowerShell as an administrator and type this command sc delete ServiceName

How do I silently install a Windows service app?

You can avoid the message box appearing by adding “/silent” to the end of the command line like so: myserviceapp.exe /install /silent

Can 32bit services run on 64bit Windows?

Yes, a 32bit service can run normally on a 64bit version of Windows. Note, however, that some network system administrators may have a Windows group policy option set up which will prevent anything other than 64bit services from running. Most don’t do this, but it is possible.

本站仅提供存储服务,所有内容均由用户发布,如发现有害或侵权内容,请点击举报
打开APP,阅读全文并永久保存 查看更多类似文章
猜你喜欢
类似文章
【热】打开小程序,算一算2024你的财运
delphi怎样编写服务程序-Service Application,编好了怎么安装这个服...
delphi中关于tapplication类的详解
Delphi 6 程序员代码编写标准指南一
delphi 虚拟桌面原理及实现
花10分钟时间来关闭你电脑上没用的服务,让你的电脑百毒不侵、提速百倍
在Delphi程序中操作注册表
更多类似文章 >>
生活服务
热点新闻
分享 收藏 导长图 关注 下载文章
绑定账号成功
后续可登录账号畅享VIP特权!
如果VIP功能使用有故障,
可点击这里联系客服!

联系客服