安装 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
,说明没有异常抛出.
我试过的:
函数执行时,会出现UAC提示,然后
过程开始。我尝试 运行ning 整个应用程序作为
管理员,但这并没有解决问题。
我还尝试将 '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
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"
当路径完全写在代码中时,遗漏的双引号很容易被注意到。但是,当使用字符串插值时,它可能会导致问题,就像我的情况一样。
我创建了一个 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
,说明没有异常抛出.
我试过的:
函数执行时,会出现UAC提示,然后 过程开始。我尝试 运行ning 整个应用程序作为 管理员,但这并没有解决问题。
我还尝试将 '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
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"
当路径完全写在代码中时,遗漏的双引号很容易被注意到。但是,当使用字符串插值时,它可能会导致问题,就像我的情况一样。