在C#中管理Windows服务(安装、启动、停止、卸载)需要使用System.ServiceProcess
命名空间以及可能的进程调用(如sc.exe
)。以下代码示例分为两部分:将程序安装为服务和停止/卸载服务。
1、将程序安装为Windows服务
2、停止并卸载Windows服务
前提条件:目标程序必须实现Windows服务逻辑(如继承自ServiceBase
的.NET程序或符合Windows服务标准的可执行文件)。
public class exeSysService
{
public static void InstallService(string serviceName, string executablePath)
{
Process process = new Process();
ProcessStartInfo startInfo = new ProcessStartInfo
{
FileName = "sc.exe",
Arguments = $"create \"{serviceName}\" binPath= \"{executablePath}\" start= auto",
WindowStyle = ProcessWindowStyle.Hidden,
Verb = "runas"
};
process.StartInfo = startInfo;
process.Start();
process.WaitForExit();
if (process.ExitCode == 0)
{
Console.WriteLine("服务安装成功!");
StartService(serviceName);
}
else
{
Console.WriteLine($"服务安装失败,错误代码: {process.ExitCode}");
}
}
private static void StartService(string serviceName)
{
using (ServiceController service = new ServiceController(serviceName))
{
if (service.Status != ServiceControllerStatus.Running)
{
service.Start();
service.WaitForStatus(ServiceControllerStatus.Running, TimeSpan.FromSeconds(30));
Console.WriteLine("服务已启动!");
}
}
}
public static void UninstallService(string serviceName)
{
StopService(serviceName);
Process process = new Process();
ProcessStartInfo startInfo = new ProcessStartInfo
{
FileName = "sc.exe",
Arguments = $"delete \"{serviceName}\"",
WindowStyle = ProcessWindowStyle.Hidden,
Verb = "runas"
};
process.StartInfo = startInfo;
process.Start();
process.WaitForExit();
if (process.ExitCode == 0)
Console.WriteLine("服务卸载成功!");
else
Console.WriteLine($"服务卸载失败,错误代码: {process.ExitCode}");
}
private static void StopService(string serviceName)
{
using (ServiceController service = new ServiceController(serviceName))
{
if (service.CanStop && service.Status != ServiceControllerStatus.Stopped)
{
service.Stop();
service.WaitForStatus(ServiceControllerStatus.Stopped, TimeSpan.FromSeconds(30));
Console.WriteLine("服务已停止!");
}
}
}
}
使用示例
ServiceInstaller.InstallService(
"MyService",
@"C:\MyApp\MyService.exe"
);
ServiceUninstaller.UninstallService("MyService");
关键注意事项
1、管理员权限:操作服务需要以管理员身份运行程序(在Visual Studio中右键项目 → 属性 → 安全性 → 勾选“启用ClickOnce安全设置”,或在清单文件中设置requestedExecutionLevel level="requireAdministrator"
)。
2、服务程序要求:
3、错误处理:添加更完善的异常处理(如服务不存在时的InvalidOperationException
)。
4、超时处理:WaitForStatus
可能因服务未及时响应而超时,需额外处理。
替代方案:使用Windows API
更高级的场景可调用Windows API(如CreateService
、OpenSCManager
),需通过P/Invoke调用advapi32.dll
,代码复杂度较高。推荐使用上述sc.exe
方案或开源库(如Topshelf)简化开发。
在 C# 中判断 Windows 服务是否已安装,可以通过 ServiceController
类来实现。以下是完整的代码示例:
using System;
using System.ServiceProcess;
using System.Collections.Generic;
public class ServiceHelper
{
public static bool IsServiceInstalled(string serviceName)
{
try
{
ServiceController[] services = ServiceController.GetServices();
foreach (ServiceController service in services)
{
if (service.ServiceName.Equals(serviceName, StringComparison.OrdinalIgnoreCase))
{
return true;
}
}
return false;
}
catch (Exception ex)
{
Console.WriteLine($"检查服务时出错: {ex.Message}");
return false;
}
}
public static bool IsServiceInstalledLinq(string serviceName)
{
try
{
return Array.Exists(ServiceController.GetServices(),
service => service.ServiceName.Equals(serviceName, StringComparison.OrdinalIgnoreCase));
}
catch (Exception ex)
{
Console.WriteLine($"检查服务时出错: {ex.Message}");
return false;
}
}
public static List<string> GetAllInstalledServices()
{
List<string> serviceNames = new List<string>();
try
{
foreach (ServiceController service in ServiceController.GetServices())
{
serviceNames.Add(service.ServiceName);
}
}
catch (Exception ex)
{
Console.WriteLine($"获取服务列表时出错: {ex.Message}");
}
return serviceNames;
}
}
class Program
{
static void Main(string[] args)
{
string serviceName = "Winmgmt";
bool isInstalled = ServiceHelper.IsServiceInstalled(serviceName);
Console.WriteLine($"服务 '{serviceName}' 是否已安装: {isInstalled}");
string nonExisting = "MyFakeService123";
bool notInstalled = ServiceHelper.IsServiceInstalled(nonExisting);
Console.WriteLine($"服务 '{nonExisting}' 是否已安装: {notInstalled}");
Console.WriteLine("\n已安装服务列表(前10个):");
var services = ServiceHelper.GetAllInstalledServices();
foreach (string name in services.Take(10))
{
Console.WriteLine($"- {name}");
}
}
}
关键说明:
1、核心方法:
ServiceController.GetServices()
这个方法返回本地计算机上所有 Windows 服务的数组。
2、检查服务是否存在:
Array.Exists(services, s => s.ServiceName.Equals(serviceName, StringComparison.OrdinalIgnoreCase));
使用 Array.Exists
配合不区分大小写的比较来检查服务是否存在
3、错误处理:
4、注意事项:
需要 System.ServiceProcess
程序集引用
应用程序可能需要以管理员权限运行才能访问某些服务信息
服务名称是系统内部名称(如 "wuauserv"),不是显示名称(如 "Windows Update")
使用场景示例:
string myService = "MyCustomService";
if (ServiceHelper.IsServiceInstalled(myService))
{
Console.WriteLine("服务已存在,跳过安装");
}
else
{
Console.WriteLine("服务未安装,执行安装操作");
}
if (ServiceHelper.IsServiceInstalled(myService))
{
Console.WriteLine("服务存在,执行卸载");
}
else
{
Console.WriteLine("服务不存在,无需卸载");
}
性能考虑:
对于需要频繁检查服务状态的场景,建议缓存服务列表:
private static ServiceController[] _cachedServices;
private static DateTime _lastRefresh = DateTime.MinValue;
public static bool IsServiceInstalledCached(string serviceName, bool forceRefresh = false)
{
try
{
if (forceRefresh || _cachedServices == null || (DateTime.Now - _lastRefresh).TotalMinutes > 5)
{
_cachedServices = ServiceController.GetServices();
_lastRefresh = DateTime.Now;
}
return Array.Exists(_cachedServices,
service => service.ServiceName.Equals(serviceName, StringComparison.OrdinalIgnoreCase));
}
catch (Exception ex)
{
Console.WriteLine($"检查服务时出错: {ex.Message}");
return false;
}
}
这种方法可以显著提高频繁调用的性能,同时保持数据的相对新鲜度。
该文章在 2025/6/2 18:52:24 编辑过