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

您所在的位置:网站首页 添加一个空白桌面 windows 服务程序和桌面程序集成(五)集成为一个EXE

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

2023-06-14 03:41| 来源: 网络整理| 查看: 265

系列文章目录链接:

windows 服务程序和桌面程序集成(一)概念介绍windows 服务程序和桌面程序集成(二)服务程序windows 服务程序和桌面程序集成(三)UDP监控工具windows 服务程序和桌面程序集成(四)桌面程序windows 服务程序和桌面程序集成(五)集成为一个EXEwindows 服务程序和桌面程序集成(六)集成安装、启动、卸载功能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 服务程序和桌面程序集成(六)集成安装、启动、卸载功能



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3