安装 C# 后,无法使用 WPF App 使用 SC.exe 创建 Windows 服务

Posted

技术标签:

【中文标题】安装 C# 后,无法使用 WPF App 使用 SC.exe 创建 Windows 服务【英文标题】:Cannot create a windows service with SC.exe using WPF App after its installation C# 【发布时间】:2021-08-01 19:16:40 【问题描述】:

我创建了一个 WPF 桌面应用程序和一个 Worker 服务(所有 .NET 6.0 预览版 3),使用 Microsoft Visual Studio 安装程序项目扩展将它们打包到一个 .MSI 安装文件中,该扩展在计算机上安装 WPF 应用程序。

虽然应用程序安装并正常运行,但我必须以某种方式实现服务安装,该服务安装应在安装 WPF 应用程序后运行。我为此创建了一个函数,它以管理员身份运行 sc.exe,并使用Process.Start() 安装服务,如下所示:

private static void InstallService()

      const string ServiceName = "SomeService";
      var path = Path.GetFullPath(@".\SomeService.exe");

      var psi = new ProcessStartInfo
      
         FileName = @"C:\Windows\system32\sc.exe",
         Arguments = $"create  ServiceName  binPath=  path  start= auto",
         Verb = "runas",
         UseShellExecute = true,
      ;

      try
      
         Process.Start(psi);
      
      catch (Exception ex)
      
         MessageBox.Show($"Installation has failed:  ex.Message + ex.StackTrace ");
      

此函数的问题在于,当应用程序在 Visual Studio 中运行以及从 Visual Studio 创建的 'bin\Release' 文件夹运行时,它可以正常执行。然后服务安装并可以启动。但是,当使用 .MSI 包安装程序时,服务不安装并且没有显示MessageBox,这表明没有抛出异常

我尝试过的:

执行该函数时,会显示一个 UAC 提示符,然后 过程开始。我尝试将整个应用程序运行为 管理员,但这并没有解决问题。

我还尝试将“bin\Release”目录中的所有文件复制到安装应用程序的目录中,并将每个文件替换为“bin\Release”中的文件,这样两个目录应该相同,但这也没有解决问题。

安装函数执行后,服务应该启动另一个函数来启动它:

private static void RunService()

      const string ServiceName = "SomeService";

      var psi = new ProcessStartInfo
      
           FileName = @"C:\Windows\system32\sc.exe",
           Arguments = $"start  ServiceName ",
           Verb = "runas",
           UseShellExecute = true,
      ;

      try
      
           Process.Start(psi);
      
      catch (Exception ex)
      
           MessageBox.Show($"Running was not approved or failed:  ex.Message ");
      

此功能在这两种情况下都可以正常工作,但显然只有在之前安装了该服务时才能使用,而这在 .MSI 安装的应用程序中是无法完成的。至于使用Process.Start()而不是ServiceController类,应用程序默认不应该以管理员身份运行,用ServiceController是不行的,所以我用Process.Start()Verb = "runas" 以管理员身份运行进程,仅在需要时显示 UAC 提示(仅在服务尚未运行时启动服务)。

有什么办法可以解决这个问题并在 .MSI 安装的 WPF 应用程序中安装 Worker Service?

【问题讨论】:

MSI安装后第一次启动应用程序时不能安装服务吗? @mm8 我无法使用我正在寻找的 WPF 应用程序安装它 - 它不会引发任何异常,但在安装函数执行后没有任何反应。但是,当它在从“bin/release/”调试应用程序/时执行时,就会安装该服务。我可以在不使用应用程序的情况下安装服务(使用命令提示符),尽管这不是我想要的,因为我想在不同的机器上/为不同的人安装应用程序。 【参考方案1】:

当我进一步分析所有可能的因素时,我终于注意到在这种情况下导致问题的原因。

通常,Visual Studio 生成的路径没有任何空格,因此它们可以写成不带双引号的命令参数。在我的情况下,包含项目文件的路径也没有任何空格,这导致没有双引号的命令可以正常执行。然而,安装路径确实包含空格,因为它被设计为更加用户友好,这导致这段代码无法按预期执行:

// the path parameter in the command will end when there will be a space somewhere in the path

Arguments = $"create  ServiceName  binPath=  path  start= auto"

path 变量只包含完整路径,没有用双引号括起来。

为防止出现此问题,必须使用双引号,并且包含 \ 符号会通知编译器这些双引号是字符串的一部分:

// the path parameter is wrapped in double quotes and will be fully read

Arguments = $"create  ServiceName  binPath= \" path \" start= auto"

当路径完全写在代码中时,很容易注意到缺少的双引号。但是,当使用字符串插值时,它可能会导致问题,就像我的情况一样。

【讨论】:

以上是关于安装 C# 后,无法使用 WPF App 使用 SC.exe 创建 Windows 服务的主要内容,如果未能解决你的问题,请参考以下文章

使用 WPF 成功连接后无法从 Access 数据库获取数据

C# wpf datagrid 动态加载数据后改变单元格颜色bug

c# winform打包后,安装上之后没法运行?

c# - 在运行时更改 App.Config 后,实体框架 ConnectionString 不会更新

通过C# WinForm控件创建的WPF WIndow窗口控件无法输入的问题

通过 C# WPF App 使用 XML 更新并插入 SQL Server 数据库