windows 服务程序和桌面程序集成(五)集成为一个EXE

news2024/9/28 11:13:12

系列文章目录链接:

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

通过前四节的介绍,相信大家已经对windows服务程序和桌面程序开发流程等很清楚了,前面讲的windows服务程序和桌面程序都还是传统的独立的EXE程序。对于windows服务程序我们仍然无法进行调试,开发的流程必须是编译成EXE文件、安装服务、启动服务、停止服务、卸载服务,检查日志,然后再根据日志(UDP消息)修改代码继续上述步骤迭代,直至服务程序满足要求。

本节我们将介绍这个系列文章的核心,就是将windows服务程序和桌面程序集成为一个EXE文件,这个EXE文件可以通过 /insall 将程序安装为服务,也可以直接双击EXE文件,启动为普通的桌面程序。

事实上,解决这个问题也比较简单,就是将windows服务程序和桌面程序启动程序合并起来,然后通过运行时是否携带 /install 或者 /uninstall 参数来判断是运行windows服务程序还是桌面程序,如果有/install 或者 /uninstall 参数则肯定是运行windows服务程序,否则就是运行桌面程序。

Windows中,安装服务程序必须是管理员权限运行 CMD才能安装,否则无法成功安装,所以我们需要程序判断当前是否是管理员权限,如果不是管理员权限,提示用户无法安装。判断当前程序是否再管理员权限下运行需要使用到uProcess_UserCode.pas单元。

下面详细介绍集成实现步骤:

一、创建一个VCL桌面程序:Service_Application_Demo.dproj

其实可以直接使用 windows 服务程序和桌面程序集成(四)桌面程序 中创建的程序来进行修改!

命名主Form单元为:uMainForm_Application.pas

修改主界面属性:

序号属性内容
1Caption桌面程序主界面
2NameForm_Application

增加4个按键:创建线程并启动、暂停线程运行、继续线程运行、停止并释放线程。也就是和windows 服务程序和桌面程序集成(四)桌面程序 中创建的程序一样。

 通过菜单 Project -> View Source 打开工程启动文件

program Service_Application_Demo;

uses
  Vcl.Forms,
  uMainForm_Application in 'uMainForm_Application.pas' {Form_Application};

{$R *.res}

begin
  Application.Initialize;
  Application.MainFormOnTaskbar := True;
  Application.CreateForm(TForm_Application, Form_Application);
  Application.Run;
end.

二、给上面的VCL桌面程序增加windows服务程序功能

1. 修改通过菜单 Project -> View Source 打开工程启动文件如下:

修改前:

program Service_Application_Demo;

uses
  Vcl.Forms,
  uMainForm_Application in 'uMainForm_Application.pas' {Form_Application};

{$R *.res}

begin
  Application.Initialize;
  Application.MainFormOnTaskbar := True;
  Application.CreateForm(TForm_Application, Form_Application);
  Application.Run;
end.

修改后:

program Service_Application_Demo;

uses
  Vcl.SvcMgr,
  Vcl.Forms,
  System.SysUtils,
  Winapi.Windows,
  uMainForm_Application in 'uMainForm_Application.pas' {Form_Application},
  uProcess_UserCode in '..\Public\uProcess_UserCode.pas',
  uWorkerThread in '..\Public\uWorkerThread.pas',
  uWindows_Service in 'uWindows_Service.pas' {Service1: TService};

{$R *.res}
var
  bIsGUI: Boolean;   //增加的变量,用来判断是windows服务程序还是桌面GUI程序

begin
  //判断是否是GUI模式
  bIsGUI := NOT is_SYSTEM_Account;   //判断是否是 SYSTEM用户?
  bIsGUI := bIsGUI AND (NOT FindCmdLineSwitch('INSTALL', ['/'], True));
  bIsGUI := bIsGUI AND (NOT FindCmdLineSwitch('UNINSTALL', ['/'], True));

  FbIsGUI := bIsGUI; //注意这个变量,在输出UDP消息的时候判断是GUI还是服务程序

  //如果有INSTALL 或者 UNINSTALL等参数,但是不是管理员权限,也是不能注册的
  if (not bIsGUI) and (not IsUserAnAdmin) then
    begin
      Application.MessageBox(PWideChar('如果携带参数: INSTALL或者UNINSTALL, 系统必须以管理员身份运行!'),'出错啦',MB_OK + MB_ICONERROR);
      Exit;
    end;

  if bIsGUI then
     begin
        Application.Initialize;
        Application.MainFormOnTaskbar := True;
        Application.CreateForm(TForm_Application, Form_Application);
        Application.CreateForm(TService1, Service1);
        Application.Run;
     end
  else
     begin
       if not Vcl.SvcMgr.Application.DelayInitialize or Vcl.SvcMgr.Application.Installing then
          Vcl.SvcMgr.Application.Initialize;
       Vcl.SvcMgr.Application.CreateForm(TService1, Service1);
       Vcl.SvcMgr.Application.Run;
     end;
end.

修改完这个文件后,程序将会出现错误,有些地方显示红色波浪线,这是因为有些单元我们还没有增加进去。

2. 增加判断是否是管理员权限单元:uProcess_UserCode.pas

 3. 增加工作线程单元:uWorkerThread.pas,这个单元就是创建WIindows服务程序时创建的单元。

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;
  FbIsGUI    : Boolean;        //是否是桌面程序

implementation

procedure Send_UDP_Info(str : string);
var
  UDPClient: TIdUDPClient;
  B : TBytes;
begin
  UDPClient := TIdUDPClient.Create(nil);
  try
    UDPClient.BroadcastEnabled := True;
    if FbIsGUI then
       str := ' (桌面程序) ' + str
    else
       str := ' (服务程序) ' + str;

    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.

 4. 增加windows服务程序主单元:uWindows_Service.pas 。这个单元就直接使用前面节中创建的独立windows服务程序的单元,将其到当前工程文件目录中。

 添加完以上单元后,目前Service_Application_Demo.exe已经是一个双模程序了,既可以当windows服务程序,也可以是普通的桌面程序。

三、完善桌面程序功能

1. 在uMainForm_Application.pas中引用 uWorkerThread.pas单元;

2. 实现 创建线程并启动、暂停线程运行、继续线程运行、停止并释放线程 四个按键的功能;

uMainForm_Application.pas单元完善后代码:

unit uMainForm_Application;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls;

type
  TForm_Application = class(TForm)
    Button1: TButton;
    Button2: TButton;
    Button3: TButton;
    Button4: TButton;
    procedure Button1Click(Sender: TObject);
    procedure Button2Click(Sender: TObject);
    procedure Button3Click(Sender: TObject);
    procedure Button4Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form_Application: TForm_Application;

implementation

uses
  uWorkerThread;

{$R *.dfm}

procedure TForm_Application.Button1Click(Sender: TObject);
begin
   //创建工作线程
  if WorkThread = nil then
     WorkThread := TWorkThread.Create;
  WorkThread.FreeOnTerminate := True;    //完成后直接释放
end;

procedure TForm_Application.Button2Click(Sender: TObject);
begin
  WorkThread.Pause;
end;

procedure TForm_Application.Button3Click(Sender: TObject);
begin
  WorkThread.Continue;
end;

procedure TForm_Application.Button4Click(Sender: TObject);
begin
  WorkThread.Terminate;
  while not WorkThread.Finished do
    begin
      Sleep(200);
    end;
  WorkThread := nil;
end;

end.

四、双模程序的使用

经过前面三步,我们已经成功的创建了一个windows服务程序和桌面程序于一体的双模程序,单独的EXE文件,既是windows服务程序,也是普通的桌面程序。

作为windows服务程序,我们可以使用 /install 和 /uninstall安装和卸载,作为桌面程序,我们可以双击EXE文件直接运行。

程序的主要功能是uWorkerThread.pas单元实现,这个单元的工作在windows服务程序和桌面程序都有引用。我们以后开发的双模程序就可以按照这个模板,把程序的功能集中在共享单元uWorkerThread.pas中,调试的时候可以按照桌面程序进行单步跟踪,调试完成满足要求后,可以按照windows服务程序来安装,作为一个真正的windows服务程序来使用。这样就真正解决了windows服务程序调试问题,也真正实现了双模程序。

虽然我们的双模程序已经完美实现了,但是当作为windows服务程序使用时需要安装,启动,卸载等,必须使用CMD(当然也可以使用其他工具),总是要使用其他工具,能否在我们的桌面程序的界面上实现windows服务程序的安装、启动、停止、卸载呢?

答案是可以的,继续看下一节....

下一篇:windows 服务程序和桌面程序集成(六)集成安装、启动、卸载功能

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/637143.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

《Python深度学习基于Pytorch》学习笔记

1.Numpy提供两种基本的对象:ndarray(n维数组对象)(用于储存多维数据)和ufunc(通用函数对象,用于处理不同的数据)。 2.numpy的主要优点:ndarray提供了很多数组化的运算&a…

springboot+vue大学生足球队管理系统 java

(1) 系统管理: 用户分为超级管理员、球队管理员、球队球员、游客,以区分不同用户的操作权限,用户的登录退出。 (2) 前台页面: 1.网站首页:展示系统简介,部分赛事信息,部分院系球队信息&#xff…

号称「碾压」LLaMA的Falcon实测得分仅49.08

作为开源模型界的扛把子,LLaMA 一直备受瞩目。 这是一组由 Meta 开源的大型语言模型,共有 7B、13B、33B、65B 四种版本。其中,LLaMA-13B 在大多数数据集上超过了 GPT-3(175B),LLaMA-65B 达到了和 Chinchill…

服务器文件同步机制配置(rsync Sersync)

参考文章链接:http://static.kancloud.cn/curder/linux/78148 在上述参考文章中,对与主从同步部署过程做了详细的操作解释,但对于三台服务器如何互相同步(即三个都是master),本文针对三台master相互同步进…

一文读懂redis持久化机制

持久化官网相关参考资料 https://redis.io/docs/manual/persistence/ 持久化就是把redis内存里面保存的数据保存磁盘中,在redis重启或者能够使得数据不会丢失。目前常用的持久化方式有:RDB方式、AOF方式以及RDB AOF两种方式 RDB持久化方式 所谓的RDB…

实现无间断的自动化:Jenkins与GitLab的定时任务工作流程

简介: Jenkins是一个流行的开源自动化服务器,而GitLab是一个强大的代码托管和协作平台。通过结合Jenkins和GitLab,我们可以建立一个强大的定时任务自动化工作流程,实现代码拉取、构建、测试和部署的自动化。本篇博客将介绍如何使…

大屏数据可视化开源项目

一、DataGear —— 数据可视化项目 官网:DataGear - 开源免费的数据可视化分析平台 DataGear 是一款开源免费的数据可视化分析平台,数据可视化看板。 功能特性: 1、多种数据源,支持运行时接入任意提供 JDBC 驱动的数据库&#…

Web网页端IM产品RainbowChat-Web的v5.0版已发布

一、关于RainbowChat-Web RainbowChat-Web是一套Web网页端IM系统,是RainbowChat的姊妹系统(RainbowChat是一套基于开源IM聊天框架 MobileIMSDK(Github地址) 的产品级移动端IM系统)。 ► 详细介绍:http://www.52im.net/thread-248…

Python的pip install安装路径修改

背景 当我们在安装python的依赖包的时候,不知道默认安装在什么位置,或者不想安装在默认的位置,这时候我们可以手动修改pip install的安装位置。 1.打开cmd窗口, 执行python -m site 输入 python -m site 这个命令可以看到目前的USER_BASE和…

HarmonyOS ArkTS Ability内页面的跳转和数据传递

HarmonyOS ArkTS Ability的数据传递包括有Ability内页面的跳转和数据传递、Ability间的数据跳转和数据传递。本节主要讲解Ability内页面的跳转和数据传递。 打开DevEco Studio,选择一个Empty Ability工程模板,创建一个名为“ArkUIPagesRouter”的工程为…

亚马逊美国站 CPC认证-儿童毛绒玩具产品 毛绒玩具的作用

毛绒玩具等毛绒东西,其实能给孩子带来愉快和安全感,接触舒适,是儿童依恋的重要部分。我们常常能见到一些孩子晚上睡觉前一定要搂着毛绒玩具、或者一定要盖着毛绒毯子才能睡,丢掉了毛绒玩具,或者盖了其他布质的被子就会…

vue时间组件重置

<el-form-item label"注册日期" label-width"210px"><el-date-picker clearablev-model"registerTime"type"daterange"range-separator"至"value-format"yyyy-MM-dd"start-placeholder"开始日期&qu…

[论文笔记] Atos: A Task-Parallel GPU Scheduler for Graph Analytics

Atos: A Task-Parallel GPU Scheduler for Graph Analytics Atos: 用于图分析的任务并行 GPU 调度程序 [Paper] [Slides] ICPP’22 摘要 提出了 Atos, 一个特别针对动态不规则应用的任务并行 GPU 动态调度框架. 支持消除依赖关系的应用的任务并行公式来暴露额外的并发性除了…

MacBook苹果笔记本电脑卡顿怎么解决?

MacBook使用时间久了之后很容易出现卡顿的问题。那么出现卡顿的原因有哪些呢&#xff1f;MacBook卡顿怎么处理呢&#xff1f;下面为大家介绍几种可能的解决方案。虽然mac系统相对来说比较稳定&#xff0c;但遇到软件崩溃的情况也会突然卡顿而无法使用。那么&#xff0c;遇上mac…

C#运行程序修改数据后数据表不做更新【已解决】

前言 近日&#xff0c;在使用C#连接数据库的时候&#xff0c;对数据库中的表做更新后&#xff0c;在当前启动项目中去显示表数据时虽然会发生一个更新&#xff0c;但是在结束程序运行后再去观察数据表中的记录时发现并没有发生一个变化&#xff0c;在重复尝试了好几次后还是同样…

【Linux】中不小心误卸载了rpm命令如何恢复?

&#x1f341;博主简介 &#x1f3c5;云计算领域优质创作者   &#x1f3c5;华为云开发者社区专家博主   &#x1f3c5;阿里云开发者社区专家博主 &#x1f48a;交流社区&#xff1a;运维交流社区 欢迎大家的加入&#xff01; 文章目录 问题复现问题解决方案补全 whereis r…

Mac电脑把位图转换成矢量图的软件

Super Vectorizer for Mac是一款强大的位图转换工具&#xff0c;运行在Mac OS平台&#xff0c;可以轻松将数位图转换为矢量图。 矢量图以其放大后图像不会失真的优点&#xff0c;在社会各处的使用范围越来越广&#xff0c;但是网络上找到的图片又往往是数位图&#xff0c;这时…

【APP Debug抓包工具】Stream - Network Debug Tool

【APP Debug工具】 Stream - Network Debug Tool

Flutter进阶篇-Local Key和Global Key

简介: key是widget、element和semanticsNode的唯一标识&#xff0c;同一个parent下的所有element的key不能重复&#xff0c;但是在特定条件下可以在不同parent下使用相同的key&#xff0c;比如page1和page2都可以使用ValueKey(1) 。 常用key的UML关系图如上&#xff0c;整体上…

阿里云安装2019版sql server服务

1、添加 Microsoft 的 yum 存储库 [rootiZ22312ginudnbnifn438Z ~]# curl -o /etc/yum.repos.d/mssql-server.repo https://packages.microsoft.com/config/rhel/7/mssql-server-2019.repo 这里地址一定要选择https://packages.microsoft.com/config/rhel/7/mssql-server-2019…