Wix 和延迟的自定义操作结果
Wix and Deferred Custom Action Result
简短版本
是否可以从用 C++ 编写的延迟自定义操作中设置 MSI 属性?如果,正如我所怀疑的那样,是否有任何其他方式将延迟自定义操作的结果传达给安装程序,以便我可以做出有条件的 ScheduleReboot
决定?
TLDR 版本
我正在为开源文件系统驱动程序 (WinFsp) 创建 Wix 安装程序。安装程序必须安装驱动程序 (FSD) 和 DLL。经过一些研究,我确定 Windows 安装程序不完全支持此类驱动程序的安装。尽管如此,我现在已经创建了一个 MSI,它可以很好地处理 install/uninstall。
但是有一个陷阱。由于各种原因,无法停止或卸载此 FSD。当用户启动卸载时,MSI 能够从 SCM 中删除 FSD 服务,然后删除 FSD 文件。即使 FSD 服务未停止,这也是可能的。 [这是 Windows 上此类驱动程序的设计!]
问题是虽然卸载已经完成,但Windows仍然加载了FSD。在这种情况下,我想执行 ScheduleReboot
和 ServiceExists
由自定义操作确定的条件:
<Binary Id="CustomActions" SourceFile="..\build$(var.Configuration)\CustomActions.dll" />
<CustomAction
Id="Param.ServiceExists"
Property="A.ServiceExists"
Value="$(var.MyProductName)" />
<CustomAction
Id="A.ServiceExists"
BinaryKey="CustomActions"
DllEntry="ServiceExists"
Execute="deferred"
Impersonate="no"
Return="ignore" />
<InstallExecuteSequence>
<Custom Action="Param.ServiceExists" Before="A.ServiceExists">REMOVE ~= "ALL"</Custom>
<Custom Action="A.ServiceExists" After="RemoveFiles">REMOVE ~= "ALL"</Custom>
<ScheduleReboot After="A.ServiceExists">(REMOVE ~= "ALL") AND SERVICEEXISTS</ScheduleReboot>
</InstallExecuteSequence>
不幸的是,我发现似乎无法从延迟的自定义操作中执行 WcaSetIntProperty
。另一方面,当谈到 Wix 时,我完全是个 n00b,就在几天前,我还没有听说过任何关于它的消息。请随时向我解释如何做事。
PS:我知道 ServiceInstall
,但它不支持文件系统驱动程序。此外,Wix Difxapp 扩展似乎不是文件系统驱动程序的最佳解决方案(我的驱动程序是旧版驱动程序,没有 INF 文件)。
更新
进一步思考这个问题,我想到了两个想法:
- 使用
RegistrySearch
直接检查注册表是否存在 FSD,而不是通过服务控制管理器。我不清楚在删除文件后是否可以 运行 a RegistrySearch
。
- 不是 运行在
RemoveFiles
之后执行 ServiceExists
延迟自定义操作,也许我应该 运行 执行 ServiceRunning
即时自定义操作检查 FSD 是否 运行ning(卸载时)。这是 FSD 服务不会被正确删除而只是被 DeleteService
标记为删除的唯一场景。我会尝试这种方法,如果可行,post 它将作为答案。
正如上次更新中承诺的那样,这里是我的答案。
我创建了一个 ServiceRunning
即时自定义操作,它在文件系统驱动程序 (FSD) 上调用 QueryServiceStatus
。即时自定义操作能够毫无问题地执行 WcaSetIntProperty
。如果驱动是运行,我使用返回的属性到ScheduleReboot
(因为FSD不能是stopped/unloaded,因此卸载后会保持"pending delete")。
这里是相关的 Wix 代码:
<Binary Id="CustomActions" SourceFile="..\build$(var.Configuration)\CustomActions.dll" />
<CustomAction
Id="Params.ServiceRunning"
Property="ServiceRunning"
Value="$(var.MyProductName)" />
<CustomAction
Id="Action.ServiceRunning"
BinaryKey="CustomActions"
DllEntry="ServiceRunning"
Execute="immediate"
Return="ignore" />
<InstallExecuteSequence>
<Custom Action="Params.ServiceRunning" Before="Action.ServiceRunning">REMOVE ~= "ALL"</Custom>
<Custom Action="Action.ServiceRunning" After="RemoveFiles">REMOVE ~= "ALL"</Custom>
<ScheduleReboot After="Action.ServiceRunning">
<![CDATA[(REMOVE ~= "ALL") AND (0 <> ServiceRunning)]]>
</ScheduleReboot>
</InstallExecuteSequence>
简短版本
是否可以从用 C++ 编写的延迟自定义操作中设置 MSI 属性?如果,正如我所怀疑的那样,是否有任何其他方式将延迟自定义操作的结果传达给安装程序,以便我可以做出有条件的 ScheduleReboot
决定?
TLDR 版本
我正在为开源文件系统驱动程序 (WinFsp) 创建 Wix 安装程序。安装程序必须安装驱动程序 (FSD) 和 DLL。经过一些研究,我确定 Windows 安装程序不完全支持此类驱动程序的安装。尽管如此,我现在已经创建了一个 MSI,它可以很好地处理 install/uninstall。
但是有一个陷阱。由于各种原因,无法停止或卸载此 FSD。当用户启动卸载时,MSI 能够从 SCM 中删除 FSD 服务,然后删除 FSD 文件。即使 FSD 服务未停止,这也是可能的。 [这是 Windows 上此类驱动程序的设计!]
问题是虽然卸载已经完成,但Windows仍然加载了FSD。在这种情况下,我想执行 ScheduleReboot
和 ServiceExists
由自定义操作确定的条件:
<Binary Id="CustomActions" SourceFile="..\build$(var.Configuration)\CustomActions.dll" />
<CustomAction
Id="Param.ServiceExists"
Property="A.ServiceExists"
Value="$(var.MyProductName)" />
<CustomAction
Id="A.ServiceExists"
BinaryKey="CustomActions"
DllEntry="ServiceExists"
Execute="deferred"
Impersonate="no"
Return="ignore" />
<InstallExecuteSequence>
<Custom Action="Param.ServiceExists" Before="A.ServiceExists">REMOVE ~= "ALL"</Custom>
<Custom Action="A.ServiceExists" After="RemoveFiles">REMOVE ~= "ALL"</Custom>
<ScheduleReboot After="A.ServiceExists">(REMOVE ~= "ALL") AND SERVICEEXISTS</ScheduleReboot>
</InstallExecuteSequence>
不幸的是,我发现似乎无法从延迟的自定义操作中执行 WcaSetIntProperty
。另一方面,当谈到 Wix 时,我完全是个 n00b,就在几天前,我还没有听说过任何关于它的消息。请随时向我解释如何做事。
PS:我知道 ServiceInstall
,但它不支持文件系统驱动程序。此外,Wix Difxapp 扩展似乎不是文件系统驱动程序的最佳解决方案(我的驱动程序是旧版驱动程序,没有 INF 文件)。
更新
进一步思考这个问题,我想到了两个想法:
- 使用
RegistrySearch
直接检查注册表是否存在 FSD,而不是通过服务控制管理器。我不清楚在删除文件后是否可以 运行 aRegistrySearch
。 - 不是 运行在
RemoveFiles
之后执行ServiceExists
延迟自定义操作,也许我应该 运行 执行ServiceRunning
即时自定义操作检查 FSD 是否 运行ning(卸载时)。这是 FSD 服务不会被正确删除而只是被DeleteService
标记为删除的唯一场景。我会尝试这种方法,如果可行,post 它将作为答案。
正如上次更新中承诺的那样,这里是我的答案。
我创建了一个 ServiceRunning
即时自定义操作,它在文件系统驱动程序 (FSD) 上调用 QueryServiceStatus
。即时自定义操作能够毫无问题地执行 WcaSetIntProperty
。如果驱动是运行,我使用返回的属性到ScheduleReboot
(因为FSD不能是stopped/unloaded,因此卸载后会保持"pending delete")。
这里是相关的 Wix 代码:
<Binary Id="CustomActions" SourceFile="..\build$(var.Configuration)\CustomActions.dll" />
<CustomAction
Id="Params.ServiceRunning"
Property="ServiceRunning"
Value="$(var.MyProductName)" />
<CustomAction
Id="Action.ServiceRunning"
BinaryKey="CustomActions"
DllEntry="ServiceRunning"
Execute="immediate"
Return="ignore" />
<InstallExecuteSequence>
<Custom Action="Params.ServiceRunning" Before="Action.ServiceRunning">REMOVE ~= "ALL"</Custom>
<Custom Action="Action.ServiceRunning" After="RemoveFiles">REMOVE ~= "ALL"</Custom>
<ScheduleReboot After="Action.ServiceRunning">
<![CDATA[(REMOVE ~= "ALL") AND (0 <> ServiceRunning)]]>
</ScheduleReboot>
</InstallExecuteSequence>