MSI Installer InstallValidate如何确定正在使用的文件?

时间:2015-10-20 23:42:40

标签: wix windows-installer

我试图找出当我卸载应用程序时如何防止Restart Manager检测到需要重新启动。

我的应用程序有一个Windows服务,它使用本机DLL(Tanuki Wrapper)并创建另一个写入某些日志文件的进程(Java)。我使用的是WiX工具集,但我对MSI安装程序本身更感兴趣。我使用Orca手动尝试了一些更改。作为参考,相关的WiX配置是(我省略了JAR等的一些其他组件):

<DirectoryRef Id="logs3327407xx">
    <Component Guid="344ec345-bdd7-4c1d-801f-55ddf9e07735" Id="logs_wrapper_log88580873x">
        <File DiskId="1" Id="fl_logs_wrapper_log88580873x" Name="wrapper.log" Source="logs\wrapper.log"/>
    </Component>
</DirectoryRef>
<DirectoryRef Id="bin97543xxxx">
    <Component Guid="67c93dd8-36ad-427f-9d79-64a07c719eea" Id="bin_wrapper_windows_x86_64_exe189026768">
        <File DiskId="1" Id="fl_bin_wrapper_windows_x86_64_exe189026768" KeyPath="yes" Name="wrapper-windows-x86-64.exe" Source="bin\wrapper-windows-x86-64.exe"/>
        <ServiceInstall Account="LocalSystem" Arguments="-s &quot;..\conf\wrapper.conf&quot; wrapper.console.flush=true" Description="My Example Service." DisplayName="My Service" ErrorControl="ignore" Id="srvc_i_bin_wrapper_windows_x86_64_exe189026768" Interactive="no" Name="MyService" Start="auto" Type="ownProcess" Vital="yes"/>
        <ServiceControl Id="srvc_c_bin_wrapper_windows_x86_64_exe189026768" Name="MyService" Remove="uninstall" Start="install" Stop="both" Wait="yes"/>
    </Component>
</DirectoryRef>
<DirectoryRef Id="bin_wrapper_native490235675">
    <Component Guid="d7e4295a-1ce5-4dd2-aa92-230caac34247" Id="bin_wrapper_native_wrapper_windows_x86_64_dll156404367">
        <File DiskId="1" Id="fl_bin_wrapper_native_wrapper_windows_x86_64_dll156404367" Name="wrapper-windows-x86-64.dll" Source="bin\wrapper\native\wrapper-windows-x86-64.dll"/>
    </Component>
</DirectoryRef>

我知道InstallValidate操作中有逻辑确定文件是否正在使用中。它将使用Restart Manager或基于MSIRESTARTMANAGERCONTROL property的FilesInUse。

如果我使用重启管理器,则打开对话框,说明需要重启。日志说:

MSI (s) (1C:7C) [12:27:14:679]: Doing action: InstallValidate
Action ended 12:27:14: MigrateFeatureStates. Return value 0.
MSI (s) (1C:7C) [12:27:14:679]: PROPERTY CHANGE: Deleting MsiRestartManagerSessionKey property. Its current value is 'f2947dee632d694f8b4f1795ff254092'.
...
MSI (s) (1C:7C) [12:27:14:679]: Component: bin_wrapper_windows_x86_64_exe189026768; Installed: Local;   Request: Absent;   Action: Absent;   Client State: Local
MSI (s) (1C:7C) [12:27:14:679]: Component: bin_wrapper_native_wrapper_windows_x86_64_dll156404367; Installed: Local;   Request: Absent;   Action: Absent;   Client State: Local
MSI (s) (1C:7C) [12:27:14:679]: Component: logs_wrapper_log88580873x; Installed: Local;   Request: Absent;   Action: Absent;   Client State: Local
...
MSI (s) (1C:7C) [12:27:14:741]: RESTART MANAGER: Detected that application with id 11368, friendly name 'java.exe', of type RmCritical and status 1 holds file[s] in use.
MSI (s) (1C:7C) [12:27:14:741]: RESTART MANAGER: Did detect that a critical application holds file[s] in use, so a reboot will be necessary.
MSI (s) (1C:7C) [12:27:14:741]: Note: 1: 1610 

它实际上并没有说出文件,但如果我禁用了重启管理器并使用FilesInUse,则不会出现对话框。这次日志说:

Info 1603. The file C:\...\wrapper-windows-x86-64.exe is being held in use by the following process: Name: wrapper-windows-x86-64, Id: 11004, Window Title: '(not determined yet)'. Close that application and retry.
MSI (s) (1C:8C) [12:33:23:458]: 2 application(s) had been reported to have files in use.
Info 1603. The file C:\...\wrapper-windows-x86-64.dll is being held in use by the following process: Name: java, Id: 8284, Window Title: '(not determined yet)'. Close that application and retry.
MSI (s) (1C:8C) [12:33:23:458]: Note: 1: 2727 2:  
MSI (c) (AC:28) [12:33:23:458]: File In Use: -wrapper-windows-x86-64- Window could not be found. Process ID: 11004
MSI (c) (AC:28) [12:33:23:458]: File In Use: -java- Window could not be found. Process ID: 8284
MSI (c) (AC:28) [12:33:23:458]: No window with title could be found for FilesInUse

有人可以解释InstallValidate如何确定哪些文件正在使用?

此外,我如何阻止重启管理器说正在使用的文件将在服务停止后发布?

作为一个附带问题,为什么Restart Manager没有显示MsiRMFilesInUse对话框?我检查了MsiRMFilesInUse Dialog的所有要求,据我所知,它们都是真的。

我记得在某处读到使用ServiceControl而不是自定义操作有助于Restart Manager知道服务使用File内的ComponentComponent。我尝试将文件添加到copying build/lib/robotremoteserver.py -> /Users/usman/kivy/kivy-ios/build/robotremoteserver/i386/PythonRemoteServer-master/iosbuild/lib/python2.7/site-packages byte-compiling /Users/usman/kivy/kivy-ios/build/robotremoteserver/i386/PythonRemoteServer-master/iosbuild/lib/python2.7/site-packages/robotremoteserver.py to robotremoteserver.pyc writing byte-compilation script '/tmp/tmpM9XgVf.py' /Users/usman/kivy/kivy-ios/dist/hostpython/bin/python -OO /tmp/tmpM9XgVf.py Could not find platform dependent libraries <exec_prefix> Consider setting $PYTHONHOME to <prefix>[:<exec_prefix>] removing /tmp/tmpM9XgVf.py running install_egg_info Removing /Users/usman/kivy/kivy-ios/build/robotremoteserver/i386/PythonRemoteServer-master/iosbuild/lib/python2.7/site-packages/robotremoteserver-devel-py2.7.egg-info Writing /Users/usman/kivy/kivy-ios/build/robotremoteserver/i386/PythonRemoteServer-master/iosbuild/lib/python2.7/site-packages/robotremoteserver-devel-py2.7.egg-info Traceback (most recent call last): File "./toolchain.py", line 1224, in <module> ToolchainCL() File "./toolchain.py", line 1040, in __init__ getattr(self, args.command)() File "./toolchain.py", line 1064, in build build_recipes(args.recipe, ctx) File "./toolchain.py", line 933, in build_recipes recipe.execute() File "/Users/usman/kivy/kivy-ios/toolchain.py", line 556, in execute self.build_all() File "/Users/usman/kivy/kivy-ios/toolchain.py", line 56, in _cache_execution f(self, *args, **kwargs) File "/Users/usman/kivy/kivy-ios/toolchain.py", line 668, in build_all self.install() File "/Users/usman/kivy/kivy-ios/toolchain.py", line 56, in _cache_execution f(self, *args, **kwargs) File "/Users/usman/kivy/kivy-ios/toolchain.py", line 794, in install self.install_python_package() File "/Users/usman/kivy/kivy-ios/toolchain.py", line 835, in install_python_package dest_dir) File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/shutil.py", line 171, in copytree names = os.listdir(src) OSError: [Errno 2] No such file or directory: '/Users/usman/kivy/kivy-ios/build/robotremoteserver/i386/PythonRemoteServer-master/iosbuild/lib/python2.7/site-packages/robotremoteserver' ,但它似乎没有任何区别。

1 个答案:

答案 0 :(得分:5)

与ServiceControl相关的InstallValidate和使用中文件的行为并不复杂。如果服务正在使用该文件,并且该服务位于ServiceControl表中并标记为在卸载时停止,那么就使用行为而言,它将忽略这些文件。将文件放在同一个组件中没有任何区别,显然Windows无法知道服务代码将关闭导致文件使用情况的进程。据我所知,无法告诉InstallValidate某些文件在卸载时确实无法使用。

当不使用Restart Manager时,您将不会获得旧式的FilesInUse对话框,因为它需要一个活动窗口,可以提示用户关闭以关闭应用程序。这就是没有活动窗口的托盘应用程序不会导致FilesInUse对话框的原因。我不能确定,但​​在我看来,引用Restart Manager的第一个日志提取实际上是IS RMFilesInUse,我认为这是你正在看到的对话框。

如果您看到的唯一正在使用的文件问题与服务将关闭的java进程有关,那么可能的解决方案是:

  1. 在卸载期间禁止所有正在使用的文件对话框。
  2. 使用ServiceControl关闭服务。
  3. 确保您的ServiceControl为Wait = 1,并且在Java进程终止之前它没有响应“停止服务”请求,假设您可以明确地将其关闭。
  4. Windows并不是那么愚蠢,因为文件在InstallValidate时正在使用,它会强制重启,但在实际删除时却不是这样。因此,如果您可以确保在他们需要删除/替换/等等的实际时间不再使用这些文件,则无需重新启动。看到对话框然后发现实际上不需要重新启动并不罕见。因此,如果您取消对话框并关闭所有内容,则不会看到重新启动请求。