windows 服务程序和桌面程序集成(二)服务程序

系列文章目录链接:

  1. windows 服务程序和桌面程序集成(一)概念介绍
  2. windows 服务程序和桌面程序集成(二)服务程序
  3. windows 服务程序和桌面程序集成(三)UDP监控工具
  4. windows 服务程序和桌面程序集成(四)桌面程序
  5. windows 服务程序和桌面程序集成(五)集成为一个EXE
  6. windows 服务程序和桌面程序集成(六)集成安装、启动、卸载功能
  7. windows 服务程序和桌面程序集成(七)效果演示及源程序下载

在我的 windows 服务程序和桌面程序集成(一)博文中介绍了Windows 中服务程序桌面程序的基本概念、两种程序的特点。

备注:  

      Windows服务程序桌面程序是两种不同的应用程序类型,它们在运行方式、交互方式和执行环境等方面存在差异。

运行方式:

        桌面程序通常是由用户手动启动的,用户可以通过图形用户界面(GUI)与其交互。而Windows服务程序通常在Windows操作系统启动时就开始运行,并在后台持续运行,通常不需要用户手动启动,也没有GUI。

交互方式:

扫描二维码关注公众号,回复: 15348512 查看本文章

        桌面程序通常通过GUI与用户进行交互,例如显示窗口、菜单、按钮、文本框等,用户可以使用鼠标、键盘等输入设备与其交互。而Windows服务程序通常不需要用户交互,它们在后台运行,执行特定的任务或提供服务,例如运行网络服务器、备份数据等。

执行环境:

        桌面程序通常在用户交互的环境中运行,例如Windows桌面、移动设备等。而Windows服务程序通常在Windows操作系统的服务控制器中运行,它们以系统级别运行,具有更高的权限和安全性,可以在系统启动时启动,一直运行到系统关闭。

        总的来说,Windows服务程序桌面程序的区别在于它们的运行方式、交互方式和执行环境等方面。Windows服务程序是一种后台程序,通常在Windows操作系统启动时就开始运行,并在后台持续运行,提供特定的服务或执行特定的任务。而桌面程序则是用户手动启动的程序,通常在GUI中显示窗口、菜单、按钮等,用户可以使用鼠标、键盘等输入设备与其交互。

本文详细介绍用Delphi 开发环境创建Windows服务程序桌面程序于一体的双模EXE。也就是说一个EXE文件,既可以表现出Windows服务程序的属性,又可以表现出桌面程序的属性,就是所谓的双模程序。

以下Delphi环境为:Delphi 11.3。如果版本不一样,也基本上是相同的,可能部分界面或者代码稍有不同而已。

一、Delphi环境下Windows服务程序创建、安装、运行步骤

这一节介绍单独的windows服务程序的创建,安装、运行,后面会介绍双模程序的创建:

1. 创建一个 Windows 服务程序:WindowsService_Demo.exe

打开Delphi IDE,选择  File -> New -> Other 

 然后选择  Delphi -> Windows  窗口中的 Windos Service 选项,然后 OK 即可!

生成好文件后,保存unit1.pas文件为:uWindows_Service.pas,保存工程文件为:WindowsService_Demo.dproj

 此时可以编译生成为EXE文件,但是这是一个空Service,没有任何功能,就相当于你创建了一个VCL桌面程序,只有一个空白的Form,没有什么实际功能。注意uWindows_Service.pas就相当于VCL桌面程序的主Form。去到源程序目录看,它也包含一个对应的dfm文件 uWindows_Service.dfm。

 对于Windows服务程序,在Delphi  的 IDE中是不能运行的,也不能进行调试运行,按下运行键或者调试键是没有反应的。只能通过工程文件右键菜单中的 Build 命令来生成EXE文件。

 

 至此我们已经成功生成了一个Windows服务程序!

重点:

  1. 所有的windows服务管理接口已经被TService类实现了。在uWindows_Service.pas单元中,我们通过TService1继承了TService,它通过事件和操作系统进行交互。
  2. 通常我们需要一个线程来独立的做我们的实际工作,TService.OnExecute事件不需要做实际的工作。例如我们创建一个uWorkerThread.pas后台线程单元来完成我们的实际工作。
  3. 后台线程(uWorkerThread.pas)随着服务的启动(OnStart事件)而启动,随着服务的停止(OnStop事件)而停止。OnExecute事件等待和处理 ServiceController命令(也就是操作系统的命令)而无需处理我们的实际工作。

一般情况下,我们的OnExecute事件处理代码如下(并没有处理我们的实际任务):

procedure TService1.ServiceExecute(Sender: TService);
begin
  while not Terminated do
  begin
    ServiceThread.ProcessRequests(false);
    TThread.Sleep(1000);
  end;
end;

2. 给 Windows 服务程序:WindowsService_Demo.exe 增加实际工作线程

给Windows服务程序增加一个新单元,名称:uWorkerThread.pas,放在当前工程文件目录的上一级目录中的子目录Public目录下(为什么放在这里?请思考...)。

 工作线程单元uWorkerThread.pas实现的目的是创建一个线程,在线程中每秒通过UDP发送一条消息。由于Windows服务程序是没有界面的,所以通过UDP通信发送一条消息到外边,这样外边的UDP监控程序就可以收到Windows服务程序发送的UDP消息,每秒钟一条消息!

uWorkerThread.pas单元代码:

unit uWorkerThread;

interface
uses
  System.Classes,
  IdUDPClient,
  IdGlobal,
  System.SysUtils;
  //Winapi.Windows;

type
  //实际工作线程类
  TWorkThread = Class(TThread)
     private
       FPaused : Boolean;   //
     protected
       constructor Create;
       procedure Execute; override;
     public
       procedure Pause;
       procedure Continue;
  End;
//服务执行的函数,UDP发送消息函数
procedure Send_UDP_Info(str : string);

var
  //工作线程变量
  WorkThread : TWorkThread;

implementation

procedure Send_UDP_Info(str : string);
var
  UDPClient: TIdUDPClient;
  B : TBytes;
begin
  UDPClient := TIdUDPClient.Create(nil);
  try
    UDPClient.BroadcastEnabled := True;
    B := TEncoding.UTF8.GetBytes(str);
    //只给本机发送,这个地方只需要给本机发送广播消息即可 2023-03-04
    UDPClient.Broadcast(TidBytes(B),8192,'127.0.0.1');  //端口号
    //广播到任何地方
    //UDPClient.Broadcast(TidBytes(B),G_UDPPort);  //端口号
  finally
    UDPClient.Free;
  end;
end;


{ TWorkThread }

procedure TWorkThread.Continue;
begin
  FPaused := False;
  Send_UDP_Info('服务继续工作....');
end;

constructor TWorkThread.Create;
begin
  FPaused := False;
end;

procedure TWorkThread.Execute;
var
  S : string;
begin
  inherited;
  while not Terminated do
  begin
    if not FPaused then
       begin
         S := FormatDateTime('YYYY-MM-DD hh:mm:ss',Now);
         Send_UDP_Info(S);
       end;
    TThread.Sleep(1000);
  end;

  Send_UDP_Info('********** 服务终止工作 **********');
end;

procedure TWorkThread.Pause;
begin
  FPaused := True;
  Send_UDP_Info('服务暂停工作!!!');
end;

end.

3. 给 Windows 服务程序:WindowsService_Demo.exe 修改属性,增加事件代码

  • 修改Windows服务程序的DisplayName属性: AAA,便于在系统服务列表程序中查看。
  •  增加Windows服务程序在系统服务中显示的属性:在ServiceAfterInstall事件中增加如下代码:
procedure TService1.ServiceAfterInstall(Sender: TService);
var
  Reg : TRegistry;
begin
  Reg := TRegistry.Create(KEY_READ or KEY_WRITE);
  try
    Reg.RootKey := HKEY_LOCAL_MACHINE;
    if Reg.OpenKey('SYSTEM\CurrentControlSet\Services\' + Name,False {如果没有就不创建了}) then
      begin
        Reg.WriteString('Description','WindowsService Demo(by SensorWU)') ;
        Reg.CloseKey;
      end;
  finally
    Reg.Free;
  end;
end;

这样在服务程序显示列表中会显示出我们的服务程序的属性信息。

  • 增加Windows服务程序的其他事件代码:

OnStart代码:

procedure TService1.ServiceStart(Sender: TService; var Started: Boolean);
begin
  //创建工作线程
  WorkThread := TWorkThread.Create;
  WorkThread.FreeOnTerminate := True;    //完成后直接释放
end;

OnPause代码:

procedure TService1.ServicePause(Sender: TService; var Paused: Boolean);
begin
  WorkThread.Pause;
  Paused := True;
end;

OnContinue代码:

procedure TService1.ServiceContinue(Sender: TService; var Continued: Boolean);
begin
  WorkThread.Continue;
  Continued := True;
end;

至此,Windows服务程序(独立程序)已经完全写好,通过工程文件右键的Build菜单就可以编译出来服务程序的EXE文件了。其功能是服务程序启动后每隔一秒钟发送一个UDP消息出来,下一节我们需要做一个UDP服务来监测这个消息,这样就能够清晰的看到Windows服务程序的运行,暂停和继续了!

4. Windows服务程序的安装、启动、暂停、继续、卸载

通过上面的步骤,我们已经编译出了Windows服务程序WindowsService_Demo.exe,下面我们来演示Windows服务程序的安装、启动、暂停、继续、卸载。

为了方便(主要是Windows系统不允许网络磁盘上的程序作为Windows服务程序),我们将编译好的WindowsService_Demo.exe拷贝到 C:\Temp目录中。

安装:

通过管理员权限运行CMD,然后进入到C:\Temp目录中

C:\Temp\WindowsService_Demo.exe /install

 安装完成后,在系统的服务列表中就可以看到:

 启动、暂停、继续:

服务启动后就可以出现:停止、暂停、重启动;

服务暂停后就可以出现:停止、恢复、重启动

       

 在服务中可以分别实现 停止、暂停、恢复、重启动

 卸载:

 卸载成功后,在系统的服务列表中将看不到了。

下一篇:windows 服务程序和桌面程序集成(三)UDP监控工具

猜你喜欢

转载自blog.csdn.net/sensor_WU/article/details/131149795
今日推荐