WIX/MSI - 是否可以制作一个软件包,在卸载时保留安装前存在的文件
我正在使用 WIX 创建安装标准文件的 MSI(无 exe、com、DLL 等)。在某些用户计算机上,MSI 中的某些文件可能已经存在。在安装过程中这不是问题,因为 MSI 会自动更新较旧的文件等。但是,在卸载过程中我遇到了问题。
用一个例子来解释是最容易的:
Joe Bloggs 在他们的计算机上有“文件 B”。该文件尚未由 MSI 软件包安装,并且无论如何也不会被 Microsoft 安装程序系统跟踪。它只是计算机上的一个普通文件。
Joe Bloggs 下载并安装我的软件包,其中包含“文件 A”、“文件 B”和“文件 C”。当他安装我的软件包时,Microsoft 安装程序系统会检查“文件 B”并确定它与我的软件包中的“文件 B”相同。因此,它不会替换“文件 B”,但会将文件 B 所属的 MSI 组件标记为已安装。
然后 Joe Bloggs 认为他不喜欢我的软件,因此卸载了我的软件包。当他执行此操作时,尽管在安装我的软件包之前存在“文件 B”,但所有 3 个文件都被删除。我的调查表明,这是因为包含“文件 B”的组件被标记为已安装。因此,当您卸载该软件包时,它会删除“文件 B”。
这有点技术性,但希望有一位 WIX / MSi 专家知道解决方案。
谢谢吉姆
I am using WIX to create MSI's which install standard files (no exe, com's, DLL's etc). On some users computers some of the files in the MSI may already exist. During the install this is not a problem as MSI automatically updates files that are older etc. However, during uninstall I hit my problem.
It is easiest to explain with an example:
Joe Bloggs has "file B" on their computer. This file has not been installed by an MSI package and is not being track by the Microsoft Installer system in anyway. It is just a normal file on the computer.
Joe Bloggs downloads and installs my package which contains "file A", "file B" and "file C". When he installs my package the Microsoft Installer system checks "file B" and establishes it is identical to the "file B" in my package. It therefore does not replace "file B" but it does mark the MSI component that file B is part of as installed.
Joe Bloggs then decides he does not like my software so uninstalls my package. When he does this all 3 files are removed despite "file B" existing before my package was installed. My investigations have established that this is because the component that contains "file B" is marked as installed. Therefore when you uninstall the package it removes "file B".
This is all a bit technical but hopefully there is a WIX / MSi expert out there that knows a solution.
Thanks
Jim
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
如果文件可能已存在于计算机上,则标记
Component/@SharedDllRefCount="yes"
如果 Windows 安装程序发现文件已存在,则会自动更新引用计数。
If the files may already exist on the machine mark
Component/@SharedDllRefCount="yes"
Windows installer will then automatically update the reference count if it finds the files already existing.
这通常是通过备份和恢复自定义操作来完成的。
基本上,您编写一个自定义操作,它可以根据收到的参数复制一些文件。然后,您可以在安装程序中使用此自定义操作两次:
This is usually done through backup and restore custom actions.
Basically, you write a custom action which can copy some files based on the parameters it receives. You can then use this custom action twice in your installer:
这是使用 MSI 时的一个已知“问题”,通常是由错误的部署策略引起的。缺乏引用计数实际上只是容易出错的部署方法的一个症状。
在几乎任何情况下,安装程序都不应干扰安装运行之前存在或可能存在的文件。这包括您自己安装的文件,这些文件由您自己的另一个安装程序进行引用计数!思考凝聚力和凝聚力耦合,只有一个安装程序应该处理每个文件。
这一一般规则通常会触发“我们的情况很特殊”这样的响应。相信我,事实并非如此。应用程序应在 Program Files 下使用自己的安装文件夹、用户设置下自己的文件夹以及共享设置中自己的文件夹。它不应该永远替换或更新共享文件,例如用户词典、排除列表或类似文件。
通常,这种方法是为了促进“开发人员的困境”,其中配置文件需要默认值才能使应用程序正常运行。完全不能接受。应用程序本身可以访问共享文件,甚至可以更新它们(如果有访问权限),但它不能用“默认设置”替换整个文件或在卸载时卸载整个文件。 在没有基本配置文件的情况下创建运行环境是应用程序的责任。然后应从应用程序内部默认值生成文件或从放置在其他位置的只读默认文件复制。
如果您在不同的安装程序之间共享配置文件,我将使用合并模块部署它们,或者简单地将包含文件的组件设置为“共享”和“永久”和“如果已经存在则绝不替换”。即使您不遵循我上面推荐的部署建议,这样做也应该是对您所描述的症状的“轻松修复”。
This is a known "problem" when using MSI and is generally caused by a bad deployment strategy. The lacking reference counting is actually merely a symptom of an error-prone deployment approach.
In almost no case should your installer interfere with files that exist, or are likely to exist, before your installation is run. This includes files you have installed yourself that are reference counted by another of your own installers! Think cohesion & coupling, only one installer should deal with each file.
This general rule normally triggers a response along the lines of "our case is special". Trust me, it isn't. An application should use its own installation folder under Program Files, its own folder under user settings, and its own folder in shared settings. It should never replace or update shared files such as user dictionaries, exclusion lists or similar.
Often such an approach is to facilitate a "developer cruch" where config files need default values for the app to function. Completely unacceptable. The application itself can access shared files, even update them if it has access, but it can not replace the whole file with "default settings" or uninstall the whole file on uninstall. It is an application responsibility to create a running environment in the absence of basic configuration files. The files should then be generated from the applications internal defaults or be copied from read-only default files placed elsewhere.
If you share config files between different installers I would deploy them with a merge module, or simply set the component(s) that contain(s) the file(s) to "shared" and "permanent" and "never replace if already exists". Doing so should be the "easy fix" to the symptom you describe, even if you don't follow the deployment advice I recommend above.
我知道的唯一方法就是破解注册表。如果在 MSI 完成创建后增加
HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\SharedDLLS\
值,则在卸载过程中 MSI 将看到该文件仍在使用中,并且不删除它。这很hacky,但它会起作用。或者您可以将文件备份到另一个位置,然后在卸载时将它们复制回来。
The only way I know would be to hack the registry. If you increment the
HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\SharedDLLS\<your dll name>
value after MSI has finished creating it, during uninstall MSI will see that the file is still in use and not remove it. This is pretty hacky, but it would work.Or you could back the files up to another location, and on uninstall, copy them back.
让我尝试添加一个比我之前写的更好的答案。看来我可能没有正确阅读问题。我将尝试将其分解为几个选项:
对于 MSI 组件,一个好的经验法则是,一旦定义了关键路径(注册表中或磁盘上的绝对路径)对于一个组件,Windows Installer 认为它“拥有关键路径”并对其进行引用计数。如果引用计数为 1,它将删除关键路径以及卸载时组件中的任何其他内容。
Let me try to add a better answer than the one I wrote before. It seems I may not have read the question properly. I will try to break this down to a few options:
A good rule of thumb with an MSI component, is that once you define a key path (absolute path in the registry or on disk) for a component, Windows Installer thinks it "owns the key path" and will reference count it. If the ref-count is 1 it deletes the key path and anything else that was in the component on uninstall.