无需服务的Windows应用程序实现

在Windows平台上开发应用程序时,经常需要实现一些后台运行、定时执行任务或保持单实例的应用。通常情况下,这需要创建一个Windows服务来实现。然而,Windows服务涉及到服务账户、权限管理等一系列复杂的问题,而且对于UI(用户界面)交互较多的应用来说,使用服务并不是一个理想的选择。本文将介绍一种无需创建Windows服务,即可实现类似功能的方法。

本项目的基本组件包括:

  • Windows(本文使用WinForms,但WPF同样适用)
  • OnClose事件处理
  • 定时器
  • 套接字/监听器用于强制单实例和“杀死”应用程序
  • InnoSetup脚本

使用代码

创建一个新的Windows项目(New Project... Windows)。

创建一个定时器。拖放一个定时器对象,设置参数,创建一个定时器处理程序。项目可能不需要定时器,没关系,如果一个事件触发窗口显示/隐藏,那就足够了。

创建一个“强制关闭”机制,创建了一个名为"CanClose"的复选框。

private void TheMessage_FormClosing(object sender, FormClosingEventArgs e) { e.Cancel = !CanClose.Checked; this.Hide(); }

创建一个单独的ForceClose()方法,设置CanClose并调用Close。

public void ForceClose() { CanClose.Checked = true; Close(); }

套接字和线程。这是最有趣的部分。所以希望应用程序的行为是单实例的。有几种好方法可以做到这一点,CodeProject上的互斥体就很好。但是,还需要它能够干净地安装/卸载,这意味着它需要强制自己关闭。为此,使用了专用端口上的套接字监听器/客户端。听起来违反直觉,但首先创建了客户端(是鸡还是蛋?!)

public void Main(string[] args) { bool killStream = args.Length > 0 && args[0] == "-kill"; try { using (TcpClient clnt = new TcpClient()) { clnt.Connect("localhost", 7231); if (clnt.Connected) { clnt.GetStream().Write(new byte[] { (byte)(killStream ? 0 : 1) }, 0, 1); // 0 - kill or 1 - show clnt.Close(); return; } } } catch (SocketException) { } // nothing listening, not already running if (killStream) // if it's a kill... don't start return; }

最后是监听器...

TcpListener lstn = new TcpListener(System.Net.IPAddress.Parse("127.0.0.1"), 7231); lstn.Start(); // So, we start a long loop listening for incoming messages while (true) { using (TcpClient clnt = lstn.AcceptTcpClient()) { byte[] buff = new byte[1]; if (1 == clnt.GetStream().Read(buff, 0, 1)) { switch (buff[0]) { case 0: // Kill request msgWindow.ForceClose(); return; case 1: // Show request msgWindow.Show(); continue; } } } }

最后,需要一个InnoSetup脚本,在尝试重新安装/卸载之前调用它,如下所示...

[Files] Source: "{Your Project}\bin\Release\AntiService.exe"; DestDir: "{app}"; Flags: ignoreversion; BeforeInstall: StopLBApp ... [Code] procedure StopLBApp(); var FileName : String; ResultCode: Integer; begin Log('Asking any existing processes to stop now'); FileName := ExpandConstant('{app}\AntiService.exe'); if FileExists(FileName) then begin if not ShellExec('', FileName, '-kill', '', SW_SHOWNORMAL, ewNoWait, ResultCode) then MsgBox('DeinitializeSetup:' #13#13 'Execution of ''' + FileName + ''' failed. ' + SysErrorMessage(ResultCode) + '.', mbError, MB_OK); end; end;
沪ICP备2024098111号-1
上海秋旦网络科技中心:上海市奉贤区金大公路8218号1幢 联系电话:17898875485