MSI/WIX:如何(自我更新)正在运行的服务
问题描述:
我必须编写一个自动更新服务,以在我们的客户端PC上更新我们公司的应用程序。更新的一个应用程序是更新程序本身。我使用WIX创建的MSI包部署所有应用程序。MSI/WIX:如何(自我更新)正在运行的服务
该服务然后用“msiexec.exe/q/i”跨过一个进程来启动无提示安装。
这适用于其他产品,但是当我想更新正在运行的服务时,该服务是启动调用安装程序的进程的服务。因此,我正在尝试更新正在运行的进程。
我该怎么办? “分叉”安装程序并退出服务?使用一些聪明的Windows内置方法?
解决方案
(见下文)
答
感谢您的输入,这里是我想出了:
我使用与MajorUpgrade支持维克斯安装程序和ServiceInstall元素安装新的服务。这将导致MSI停止服务并升级安装。
现在,要从内更新服务,我需要异步启动安装程序,然后允许停止正在运行的服务。
基本上,我们需要调用:
msiexec /package path_to_msi /quiet
由于CreateProcess的需要的完整路径的可执行文件,我用SHGetKnownFolderPath检索系统
// 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";
现在的SYSTEM32路径,我们启动这一进程:
// 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");
我们完成了。
安装程序现在将指示服务停止,请确保正确处理!
新服务将被安装,并希望在几秒钟内恢复运作。
完成;-)
如果有人需要更多的细节,只需要问。
最安全的方法可能是临时安装第二个服务来代表您的服务进行升级。但实际上,启动一个子进程应该也是一样,除了边缘情况,例如机器在错误时刻重启。 (可能会有更聪明的解决方案涉及Windows Installer,因此其他人可能有更好的主意。) –
这与自定义卸载过程需要卸载自身的问题相同。一些可行的方法是将一个小的外部代码文件(不需要有exe后缀)复制到临时文件夹和CreateProcess服务中。它可能有代码等待你完成更新之前完成。将它置于临时状态通常不是问题,因为人员和流程将其清除。 – PhilDW
我不认为msiexec关心哪个进程创建它。在任何情况下,如果MSI的操作停止并替换服务,然后重启服务,则应该没有问题 - 只要该服务在预期的时间范围内成功停止,即可响应停止信号。更新正在运行的服务很常见。请用一些代码来编辑问题以帮助显示问题。 –