安装 C# 后,无法使用 WPF 应用程序使用 SC.exe 创建 windows 服务

Cannot create a windows service with SC.exe using WPF App after its installation C#

我创建了一个 WPF 桌面应用程序和一个 Worker Service(都是 .NET 6.0 预览版 3),使用 Microsoft Visual Studio Installer Projects 扩展将它们打包在一个 .MSI 安装文件中,它安装了 WPF 应用程序在机器上。

虽然应用程序安装并正常运行,但我不得不以某种方式实现服务安装,这应该 运行 在安装 WPF 应用程序之后。我为此创建了一个函数,运行s 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 中为 运行 并且在 [=61= 中为 运行 时,它会正确执行] 由 Visual Studio 创建的文件夹。然后 安装 并可以启动该服务。但是使用.MSI包安装程序时,服务没有安装,也没有显示MessageBox,说明没有异常抛出.

我试过的:

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

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 class,应用程序不应该运行默认为管理员,它是ServiceController 不可能,所以我将 Process.Start()Verb = "runas" 一起使用 运行 作为管理员的进程仅在需要时显示 UAC 提示(仅在需要时启动服务还没有 运行ning).

有没有办法解决这个问题并在 .MSI 安装的 WPF 应用程序中安装辅助服务?

随着我进一步分析所有可能的因素,我终于注意到是什么导致了这个问题。

通常,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"

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