如何在WIX安装器中仅当存在多用户会话时触发ScheduleReboot
实现WIX安装器仅在多用户登录时触发ScheduleReboot
这是个很贴合实际的需求——开发工具部署时强制重启要是打断了多个用户的工作体验可不好,得精准判断场景再触发。咱们来一步步实现:
为啥内置条件搞不定?
WIX的内置属性和条件里没有直接提供“当前登录用户数/活跃会话数”的判断,因为这需要调用Windows系统的会话管理API,所以必须靠自定义动作来实现。
具体实现步骤
1. 编写自定义动作:统计活跃用户会话数
你需要写一个自定义动作,调用Windows的WTSEnumerateSessions API来获取当前系统的所有会话,然后统计状态为WTSActive的会话数量(这对应已登录且活跃的用户)。这里用C++示例,因为兼容性更好(支持Windows XP):
#include <windows.h> #include <Wtsapi32.h> #pragma comment(lib, "Wtsapi32.lib") UINT __stdcall CheckMultiUserSession(MSIHANDLE hInstall) { UINT uiRetVal = ERROR_SUCCESS; DWORD dwCount = 0; PWTS_SESSION_INFO pSessionInfo = NULL; // 枚举所有会话 if (!WTSEnumerateSessions(WTS_CURRENT_SERVER_HANDLE, 0, 1, &pSessionInfo, &dwCount)) { uiRetVal = GetLastError(); goto Cleanup; } int activeSessions = 0; for (DWORD i = 0; i < dwCount; i++) { // 统计活跃状态的会话 if (pSessionInfo[i].State == WTSActive) { activeSessions++; } } // 设置自定义属性MultiUserLoggedIn,1表示多用户,0表示单用户 MsiSetProperty(hInstall, L"MultiUserLoggedIn", activeSessions > 1 ? L"1" : L"0"); Cleanup: if (pSessionInfo != NULL) { WTSFreeMemory(pSessionInfo); } return uiRetVal; }
2. 在WIX中注册自定义动作并设置条件
把编译好的自定义动作DLL加入你的WIX项目,然后在Product.wxs里配置:
<!-- 引入自定义动作DLL --> <Binary Id="CustomActions.dll" SourceFile="path\to\CustomActions.dll" /> <!-- 定义自定义动作 --> <CustomAction Id="CheckMultiUserSession" BinaryKey="CustomActions.dll" DllEntry="CheckMultiUserSession" Execute="immediate" Return="check" /> <!-- 在执行序列中插入自定义动作,放在ScheduleReboot之前 --> <InstallExecuteSequence> <Custom Action="CheckMultiUserSession" Before="ScheduleReboot">NOT Installed OR REINSTALL</Custom> <!-- 只有当MultiUserLoggedIn=1时才执行ScheduleReboot --> <ScheduleReboot After="InstallFinalize">MultiUserLoggedIn="1"</ScheduleReboot> </InstallExecuteSequence>
3. 兼容性注意事项
- Windows XP兼容性:
WTSEnumerateSessions在XP及以上系统都支持,编译时要确保目标平台设置为Windows XP(比如C++项目的平台工具集选v141_xp之类的)。 - 权限:自定义动作是immediate执行,不需要提升权限就能读取会话信息,所以不用担心权限问题。
测试验证
- 单用户登录时:安装后不会触发重启提示。
- 多用户登录(比如远程桌面+本地用户):安装后会弹出重启提示。
内容的提问来源于stack exchange,提问作者Yuval Perelman
相关产品推荐
相关产品推荐

