5

我们已经构建了一个在客户端机器上运行的 Windows 服务,它偶尔会下载自己的更新版本,然后执行自我更新:安装新服务,启动它,停止旧服务,并最终将其删除。该服务无法直接停止自身并执行其他操作,因此它会旋转另一个可执行文件,该可执行文件会完成一些工作。做到这一点很棘手,当使用较新的 .Net Framework 构建较新的服务时(例如最近从 .Net 2.0 切换到 .net 4.0),这尤其糟糕。问题是 .Net 2.0 库无法在 .Net 4.0 服务上运行。

现在,一种方法是让旧版本的服务旋转一个新版本附带的帮助程序,但是......如果它的行为必须以一种破坏性的方式改变怎么办?我觉得不混淆版本更安全,即使有些东西通常保持不变 - 有助于降低设计复杂性。

现在,似乎有一种在 Windows 服务上运行的 .Net 版本中立方式:该sc.exe工具:http: //support.microsoft.com/kb/251192

我想知道这是否真的是我正在寻找的银弹。现在,因为我将以编程方式调用这个人,并检查错误,所以我不妨为此使用一个 API。理想情况下,我将拥有一个本地 C++ 项目,该项目编译为与 SC.exe 交互的本地 exe。这可能吗?如果没有,那么我该如何在不同的计算机上查找 sc.exe?它们可以是 32 位或 64 位,并运行从 Win XP SP2/3 开始的任何 Windows 版本。

如果您对我的问题、一些巧妙的想法或对我在这里提出的确切问题有任何疑问,请告诉我。


编辑:如果我尝试使用 2.0 代码安装 4.0 服务,我会收到与我一样的错误:

> C:\Windows\Microsoft.NET\Framework\v2.0.50727\InstallUtil.exe MyService4.exe

Microsoft (R) .NET Framework 安装实用程序版本 2.0.50727.4927 版权所有 (c) Microsoft Corporation。版权所有。

初始化安装时发生异常:System.BadImageFormatException:无法加载文件或程序集“file:///[path]\MyService4.exe”或其依赖项之一。此程序集由比当前加载的运行时更新的运行时构建,并且无法加载。

4

4 回答 4

2

sc.exe 实际上始终位于同一路径:%windir%\System32\sc.exe(x64 使用 System32 处理 64 位二进制文​​件:-)。不知道您当前的设置如何,但如果您有,或者可以切换到 MSI - 它可以运行自定义安装操作,可以是您的新 .exe 配置文件,用于 SCM API 或仅启动 sc.exe 2-3 次停止、配置、启动。从技术上讲,您甚至可以使用 .cmd 作为 MSI 中的自定义安装操作,但它可能看起来有点难看(用户看到 cmd 窗口即将出现)。

如果你想使用 SCM API 并且你知道你的 C++,那绝对是最好的方法——中间没有层来搞砸。此外,一旦您有单独的二进制文件仅用于安装任务,您就不受 .NET 嵌入式安装过程的约束 - 您可以从 C# 和 C++ 获得相同的 NT API。关键是执行管理任务以停止、启动、配置等服务的二进制文件必须与服务本身的二进制文件不同——这是 .NET 的问题——混为一谈。

由于您正在进行重大切换,如果您之前的安装不是在 MSI 下,那么新的 MSI 将无法自行处理所有内容,因此您可能希望从字面上删除 .cmd 文件以停止并清理使用 sc.exe 的旧服务,只需启动干净,然后启动新的安装二进制文件 - 不管它是什么。MSI 将停止并卸载窗口服务,但前提是它之前由 MSI 安装。那样有点粘:-)

于 2010-08-17T08:17:26.630 回答
1

我不确定你的意思是什么:

问题是 .Net 2.0 库无法在 .Net 4.0 服务上运行。

该类ServiceController能够控制任何服务,甚至是本地服务。我还没有尝试过,但我相信这个ServiceInstaller类也可以用来(卸载)安装任何服务。

如果ServiceController并且ServiceInstaller不能满足您的需求,我建议直接包装本机 API 而不是sc.exe. MSDN 文档应该可以帮助您入门;您将需要服务控制管理器功能。该sc.exe程序只是围绕 SCM API 的一个瘦命令行包装器。

于 2010-08-06T22:01:16.863 回答
1

作为更新包的一部分,包括一个名称在版本之间不会改变的可执行文件,例如 Setup.exe :-)

然后,当更新逻辑作为新进程启动时,该工具会执行所有设置工作。它应该使用与包的其余部分相同的框架版本进行编译,以避免 CLR 版本控制问题。

我在现有ServiceInstaller类中遇到的最大问题是缺乏对更新服务功能的支持,例如描述和故障/恢复操作。为了解决这个问题,我从 CodeProject 调整了 Narendra (Neil) Baliga 的代码并改用ServiceInstallerEx该类。他的代码包括调用相同的 Windows API所需的p-invoke 定义SC.exe

有点相关:如果您的更新要求与我之前使用的相似,我建议安装到并排文件夹(其名称包括版本/发行号),并保留最后 2 或 3 个以允许回滚。将当前版本的路径传递给设置工具,以便它知道当前的播放状态。

于 2010-08-12T15:31:44.147 回答
1

您的本机 C++ 应用程序可以调用此处记录的函数:http: //msdn.microsoft.com/en-us/library/ms685942 (v=VS.85).aspx(其他人提到的 SCM API)

你会想做一些类似的事情

OpenSCManager
OpenService (or CreateService)
ChangeServiceConfig
CloseServiceHandle
于 2010-08-18T13:41:15.257 回答