本文介绍了Wix - ServiceControl 启动需要四分钟才能失败,应该是 30 秒的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我的服务在安装过程中自动启动...

My service automatically starts during install...

<ServiceControl Id="StartService" Start="install" Stop="both" Remove="uninstall" Name="HeskaGateway" Wait="yes" />

如果我为服务提供有效的连接字符串,它就可以正常工作.如果我提供了错误的连接字符串,则服务会很快启动和停止……当我转到服务"并手动启动时,我会看到这一点.根据 MSI ServiceControl Table 上的文档,yes"的等待值变为 1,这意味着它应该等待 30 秒然后失败.需要4分7秒.为什么这么久?

And it works fine if I provide the service with a valid connection string. If I provide a bad connection string the service starts and stops very quickly... I see this when I go to Services and do a manual start. According to the documentation on MSI ServiceControl Table, a Wait value of "yes" turns into a 1 which means it should wait for 30 seconds and then fail. It takes 4 minutes and 7 seconds. Why so long?

MSI (s) (6C:78) [16:36:41:932]: Executing op: ServiceControl(,Name=HeskaGateway,Action=1,Wait=1,)
StartServices: Service: Heska Gateway
MSI (s) (6C:78) [16:40:48:862]: Note: 1: 2205 2:  3: Error 
MSI (s) (6C:78) [16:40:48:862]: Note: 1: 2228 2:  3: Error 4: SELECT `Message` FROM `Error` WHERE `Error` = 1920 
Error 1920. Service 'Heska Gateway' (HeskaGateway) failed to start.  Verify that you have sufficient privileges to start system services.

我从来没有发现我真正的问题是什么.我还遇到了安装顺序错误,因为我的 CustomAction(延迟)将在 ServiceStart 之后触发,它会编辑 JSON 文件中的连接字符串.在延迟的自定义操作之后尝试移动 ServiceStart 很糟糕.所以我取消了 ServiceControl 条目的启动,然后添加了另一个静默运行SC.EXE start HeskaGateway"的自定义操作.我将在下面记录下来作为解决方案.

I never got to find out what my real problem was. I also had an installation sequencing error because my CustomAction (deferred) which would edit the connection string in the JSON file was triggering AFTER the ServiceStart. Trying to move the ServiceStart after that deferred custom action was awful. So I killed off the start from the ServiceControl entry and then added another custom action which silently ran "SC.EXE start HeskaGateway". I'll document that below as a solution.

推荐答案

安装程序有一个自定义 UI,它要求用户复制并粘贴支持部门提供给他们的连接字符串.安装程序使用延迟的 CustomAction 编辑应用程序文件夹中的 JSON 文件.它被推迟是因为它需要在文件写入磁盘之后进行,并且还需要具有提升的权限.这一切都很好,直到我决定让服务在安装结束时"自行启动.我的第一次尝试是使用

The installer has a custom UI which asks the user to copy-paste their connection string given to them from support department. The installer edits a JSON file in the app folder using a deferred CustomAction. It is deferred because it needed to be after the files are written to the disk and it also needed to have elevated permissions. This all worked great until I decided to have the service start itself "at the end" of the installation. My first attempt was to use a

<ServiceControl Id="StartService" Start="install" ...>

但这需要 4 分钟才能失败.故障排除表明该服务是在将连接字符串写入 JSON 文件的自定义操作之前启动的.我需要将服务开始延迟到自定义操作之后.我考虑在它自己的组件中添加第二个 ServiceControl 条目,该条目可以在很晚之后进行调度,但这让我感觉不舒服,我将中断卸载和修复安装.所以,我只是在 JSON 文件编辑之后添加了另一个延迟的自定义操作.该新操作执行SC.EXE start MyServiceName".SC.EXE 是一种非阻塞的服务启动方式,无论成功与否,都会很快结束.

But that was taking 4 minutes to fail. Troubleshooting showed that the service was being started BEFORE the custom action which writes the connection string into the JSON file. I needed the service start to be delayed till after the custom action. I looked at adding a second ServiceControl entry into its own component that could be scheduled much later but that gave me an uncomfortable feeling that I was going to break uninstall and repair installs. So, I just added another deferred custom action sequenced right after the JSON file edit. That new action executes "SC.EXE start MyServiceName". SC.EXE is a non-blocking way to start services so succeed or fail, it will finish quickly.

我的最终解决方案:

 <Component Id="MyCloudSync.exe" Guid="{generate-your-own-guid}">
    <File Id="MyCloudSync.exe.file" KeyPath="yes" Source="$(var.RELEASEBINARIES)\MyCloudSync.exe" />
    <ServiceInstall Id="MyCloudSync.exe"
          Type="ownProcess"
          Name="MyGateway"
          DisplayName="My Gateway"
          Description="Synchronizes laboratory data with Cloud"
          Start="auto"
          ErrorControl="normal" />
    <!--Start is performed by a customer action that calls SC.EXE so it can be delayed after the custom action that writes the JSON file -->
    <ServiceControl Id="StartService" Stop="both" Remove="uninstall" Name="MyGateway" Wait="yes" /> 
  </Component>

您应该注意到上面的 ServiceControl 条目没有start="GetConnectionString 和 SetConnectionString 调用的 DLL 是我自己制作的.Wix 有自己的自定义操作,可以安静地运行命令行... WixQuietExec

You should note that the ServiceControl entry above does not have a "start="The DLL that GetConnectionString and SetConnectionString calls is one of my own making. Wix has its own custom action for running command lines quietly... WixQuietExec

 <CustomAction Id= "GetConnectionString"
                  BinaryKey="MyCustomActions"
                  DllEntry="GetConnectionString"
                  Execute="immediate"/>
    <CustomAction Id= "SetConnectionString"
                  BinaryKey="MyCustomActions"
                  Impersonate="no"
                  DllEntry="SetConnectionString"
                  Execute="deferred"/>
    <CustomAction Id="SetConnectionStringDeferredParams"
                  Property="SetConnectionString"
                  Value="&quot;[INSTALLFOLDER]&quot;&quot;[CONNECTIONSTRING]&quot;" />
    <Property Id="QtExecStartService" Value="&quot;SC.EXE&quot; start MyGateway"/>
    <CustomAction Id="QtExecStartService" 
                  BinaryKey="WixCA" 
                  DllEntry="WixQuietExec" 
                  Impersonate="no"
                  Execute="deferred" 
                  Return="ignore"/>

启动服务只是一种方便,因此安装程序可以防止转到 Services.msc 执行启动或需要重新启动.所以我使用了 Return="ignore".此外,SC.EXE 只是将服务置于开始挂起"状态,因此除非您的服务不存在,否则它可能不会返回太多错误.

Starting the service is just a convenience so for the installer to prevent going to Services.msc to perform the start or requiring a reboot. So I used Return="ignore". Also SC.EXE just puts the service into "Start Pending" so it probably can't return much of an error unless your service doesn't exist.

注意:WixQuietExec 记录在此处.确保引用 EXE 并为您的属性提供与使用 WixQuietExec 的 CustomAction 相同的 ID.该信息位于延迟执行"下,但我第一次尝试时仍然出错.

NOTE: WixQuietExec is documented here. Make sure to quote the EXE and give your property the same Id as your CustomAction that uses WixQuietExec. That info is under "Deferred Execution" but I still got it wrong on my first try.

这篇关于Wix - ServiceControl 启动需要四分钟才能失败,应该是 30 秒的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!