Wix 3.10.3,Installer是一个包装msi的自定义引导程序。我已经实现了安装/卸载和修改功能。
MSI安装了几个服务,其中至少有一个服务与PCI驱动程序接口 - 当我添加或删除PCI组件时,我需要停止并重新启动与所述组件接口的服务,以防止可怕的#34;必须重启"场景。
我发现我可以将ServiceControl元素添加到安装驱动程序的组件中,但是,它也可以在卸载应用程序时启动服务。
我读了一些关于"共享组件"的提及,虽然没有太多关于它的文档,这表明这将是这种情况下的方法。
<Fragment>
<Component Id="PCIDriver_SvcCtl" Directory="INSTALLDIR" Guid="{5EAB2128-228D-44BE-950F-5F258B94BFED}" Win64="$(var.Win64)" >
<CreateFolder/>
<!-- Any action but uninstall. -->
<Condition>NOT REMOVE~="ALL"</Condition>
<ServiceControl Id="Service1_SvcCtl" Name="service1" Start="both" Stop="both" Wait="no" />
<ServiceControl Id="Service2_SvcCtl" Name="service2" Start="both" Stop="both" Wait="no" />
</Component>
</Fragment>
然后,在我的Product.wxs中,对于需要它的功能(安装PCI驱动程序),我补充道:
<ComponentRef Id="PCIDriver_SvcCtl" />
可能与我的问题无关,但是,与重启管理器相关,我在Product.wxs中设置了以下Restart Manager属性:
<Property Id="MSIRMSHUTDOWN" Value="1" />
因此,当我通过Modify添加/删除PCI驱动程序时,我的组件运行,停止然后启动服务,但是,当我卸载整个应用程序时,它也会运行。由于有两个服务,当它们被删除并且调用它们来启动它们时,它会为卸载增加两分钟(因为重启尝试两次,每个服务器等待时间为30秒)。
我需要设置什么条件才能避免在MSI卸载时调用此组件,但允许它在修改期间运行?或者,我需要以不同的方式创作吗?谢谢!
答案 0 :(得分:0)
如果我了解您正在尝试正确执行的操作,则只需在ServiceControl表中屏蔽msidbServiceControlEventUninstallStop值即可。这是MSI记录的方式,而不是如何在WiX中进行,但它应该让你开始。
答案 1 :(得分:0)
我放弃了尝试以“wix方式”解决它并回到自定义操作。
修改自定义操作C#代码以添加两种方法来停止和启动命名服务:
using System.ServiceProcess;
/**************************************************************************\
*
* Function: StopService
*
* Purpose: Stops the named service.
*
***************************************************************************/
[CustomAction]
public static ActionResult StopService(Session session)
{
session.Log("Begin StopService Custom Action");
string serviceName = session.CustomActionData["SERVICENAME"];
try
{
if (!string.IsNullOrEmpty(serviceName))
{
ServiceController sc = new ServiceController(serviceName);
// Start the service if the current status is any state other than running or start pending.
if (!(sc.Status.Equals(ServiceControllerStatus.Stopped))
&& !(sc.Status.Equals(ServiceControllerStatus.StopPending)))
{
sc.Stop();
}
}
}
catch (Exception ex)
{
session.Log("Failed to stop service " + serviceName + " : " + ex.ToString());
return ActionResult.Failure;
}
finally
{
session.Log("End StopService Custom Action");
}
return ActionResult.Success;
}
/**************************************************************************\
*
* Function: StartService
*
* Purpose: Starts the named service.
*
***************************************************************************/
[CustomAction]
public static ActionResult StartService(Session session)
{
session.Log("Begin StartService Custom Action");
string serviceName = session.CustomActionData["SERVICENAME"];
try
{
if (!string.IsNullOrEmpty(serviceName))
{
ServiceController sc = new ServiceController(serviceName);
// Start the service if the current status is any state other than running or start pending.
if (!(sc.Status.Equals(ServiceControllerStatus.Running))
&& !(sc.Status.Equals(ServiceControllerStatus.StartPending)))
{
sc.Start();
}
}
}
catch (Exception ex)
{
session.Log("Failed to control service " + serviceName + " : " + ex.ToString());
return ActionResult.Failure;
}
finally
{
session.Log("End StartService Custom Action");
}
return ActionResult.Success;
}
接下来,在我的Product.wxs中,自定义操作定义(两个服务,每个服务都要停止和启动,另外一个用于设置要对其执行操作的服务名称):
<!-- These next CA's relate to stopping and starting key services prior to Modifying the PCI feature state. -->
<CustomAction Id="CAL_StopService_Service1.SetProperty" Property="CAL_StopService_Service1"
Value="SERVICENAME=$(var.Service1_Service_Name)" />
<CustomAction Id="CAL_StopService_Service1" DllEntry="StopService" BinaryKey="CAL_dll" Execute="deferred" Return="ignore" />
<CustomAction Id="CAL_StopService_Service2.SetProperty" Property="CAL_StopService_Service2"
Value="SERVICENAME=$(var.Service2_Service_Name)" />
<CustomAction Id="CAL_StopService_Service2" DllEntry="StopService" BinaryKey="CAL_dll" Execute="deferred" Return="ignore" />
<CustomAction Id="CAL_StartService_Service1.SetProperty" Property="CAL_StartService_Service1"
Value="SERVICENAME=$(var.Service1_Service_Name)" />
<CustomAction Id="CAL_StartService_Service1" DllEntry="StartService" BinaryKey="CAL_dll" Execute="deferred" Return="ignore" />
<CustomAction Id="CAL_StartService_Service2.SetProperty" Property="CAL_StartService_Service2"
Value="SERVICENAME=$(var.Service2_Service_Name)" />
<CustomAction Id="CAL_StartService_Service2" DllEntry="StartService" BinaryKey="CAL_dll" Execute="deferred" Return="ignore" />
最后,在InstallExecuteSequence中对自定义操作进行排序。停止的条件是:PCI功能的状态和操作正在发生变化,并且安装了服务组件本身。对于启动,与停止相同的基本检查,以及检查以确保我们不卸载应用程序。
<!-- Manage services affected by PCI feature. -->
<Custom Action="CAL_StopService_Service1.SetProperty" Before="CAL_StopService_Service1" />
<Custom Action="CAL_StopService_Service2.SetProperty" Before="CAL_StopService_Service2" />
<Custom Action="CAL_StartService_Service1.SetProperty" Before="CAL_StartService_Service1" />
<Custom Action="CAL_StartService_Service2.SetProperty" Before="CAL_StartService_Service2" />
<Custom Action="CAL_StopService_Service1" Before="StopServices">
<![CDATA[(&PCI <> !PCI) AND (?Service1_service = 3)]]>
</Custom>
<Custom Action="CAL_StopService_Service2" Before="StopServices">
<![CDATA[(&PCI <> !PCI) AND (?Service2_service = 3)]]>
</Custom>
<Custom Action="CAL_StartService_Service1" After="StartServices">
<![CDATA[((&PCI <> !PCI) AND (?Service1_service = 3)) AND NOT REMOVE~="ALL"]]>
</Custom>
<Custom Action="CAL_StartService_Service2" After="StartServices">
<![CDATA[((&PCI <> !PCI) AND (?Service2_service = 3)) AND NOT REMOVE~="ALL"]]>
</Custom>
解决手头的问题。批判?建议改善?