【问题标题】:MSI/WIX: How to (self-)update a running serviceMSI/WIX:如何(自我)更新正在运行的服务
【发布时间】:2016-08-15 13:08:59
【问题描述】:

我必须编写一个自动更新服务来更新我们客户 PC 上的公司应用程序。要更新的应用程序之一是更新程序本身。我使用使用 WIX 创建的 MSI 包部署所有应用程序。

该服务然后使用“msiexec.exe /q /i”跨越一个进程以启动静默安装。

这适用于其他产品,但是当我想更新正在运行的服务时,该服务是启动调用安装程序的进程的服务。因此,我正在尝试更新正在运行的进程。

我该怎么做呢? “分叉”安装程序进程并退出服务?使用一些巧妙的 Windows 内置方法?

【问题讨论】:

  • 最安全的方法可能是临时安装第二个服务来代表您的服务进行升级。但在实践中,启动子进程应该也能正常工作,除了边缘情况,比如机器在错误的时刻重新启动。 (可能有更聪明的解决方案涉及 Windows 安装程序,所以其他人可能有更好的主意。)
  • 和自定义卸载过程一样的问题,需要自行卸载。可行的方法是拥有一个小的外部代码文件(不需要具有 exe 后缀),您可以将其复制到临时文件夹和服务中的 CreateProcess。它可能有等待您完成更新之前的代码。将其留在 temp 中通常不是问题,因为人员和流程会将其清除。
  • 我认为 msiexec 并不关心创建它的进程。在任何情况下,如果 MSI 的操作停止并替换服务然后重新启动它,则应该没有问题——只要服务在预期的时间范围内成功停止并没有未能响应停止信号。更新正在运行的服务是很常见的。请edit这个问题用一些代码来帮助显示问题。

标签: windows wix windows-installer


【解决方案1】:

感谢您的意见,这是我想出的:

我正在使用具有 MajorUpgrade 支持和 ServiceInstall 元素的 WIX 安装程序来安装新服务。这将导致 MSI 停止服务并升级安装。

现在,要从内部更新服务,我需要异步启动安装程序,然后停止正在运行的服务。

基本上我们需要调用:

msiexec /package path_to_msi /quiet

由于 CreateProcess 需要可执行文件的完整路径,我使用 SHGetKnownFolderPath 来检索系统上的 SYSTEM32 路径

// note: FOLDERID_SystemX86 will return 32 bit version of system32 regardless of application type
PWSTR str = nullptr;
if (SHGetKnownFolderPath(FOLDERID_SystemX86, KF_FLAG_DEFAULT, NULL, &str) != S_OK)
  throw std::runtime_error("failed to retrieve FOLDERID_SystemX86");
std::string exe = ...path to msiexec...;
std::string options = " /package \"path_to_msi\" /quiet";

现在,我们开始这个过程:

// start process
STARTUPINFO si;
PROCESS_INFORMATION pi;

ZeroMemory(&si, sizeof(si));
si.cb = sizeof(si);
ZeroMemory(&pi, sizeof(pi));

if (!CreateProcess(exe.c_str(),        // application name
                 options.c_str(),      // Command line options
                 NULL,                 // Process handle not inheritable
                 NULL,                 // Thread handle not inheritable
                 FALSE,                // Set handle inheritance to FALSE
                 0,                    // No creation flags
                 NULL,                 // Use parent's environment block
                 NULL,                 // Use parent's starting directory 
                 &si,                  // Pointer to STARTUPINFO structure
                 &pi))                 // Pointer to PROCESS_INFORMATION structure
  throw std::runtime_error("CreateProcess failed");

我们完成了。

安装程序现在将发出停止服务的信号,请确保正确处理!

新服务将被安装,并有望在几秒钟内恢复运行。

完成;-)

如果有人需要更多详细信息,请尽管问。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-07-16
    • 1970-01-01
    • 1970-01-01
    • 2018-04-13
    • 2020-09-05
    • 1970-01-01
    • 2011-02-05
    相关资源
    最近更新 更多