我弄乱了多台服务器上基于 WiX 的安装程序,以便它在卸载过程中不再删除文件或组件(甚至其他功能)。 MSI 日志显示所有无法卸载的组件上的 PreviouslyPinned=1。
我没有什么奇特的事情,比如使用 SharedDll 计数,甚至在不同安装程序之间共享组件。
我想我已经追踪到了我的 WiX 代码的特定修订版。我做了几件蠢事。我(无意中)创建了一个带有空白 Guid 的非托管组件
<Component Id="file.ext" Guid="">
<File .../>
<Component>
,并且还更改了另一个组件的文件位置和 Id(但不是 Guid)。早期版本中存在的所有组件均显示 PreviouslyPinned=1 并且不会卸载,并且在此版本之后添加的新组件可以正确安装/卸载。
如何让安装程序恢复正常并删除这些以前固定的组件?
I've messed up my WiX-based installer on multiple servers so that it no longer removes files or components (or even other features) during an uninstall. The MSI log shows that PreviouslyPinned=1 on all the components that won't uninstall.
I don't have anything fancy going on like using SharedDll count or even shared components among different installers.
I think I've tracked it down to a particular revision of my WiX code. I did a couple of stupid things. I (unintentionally) created an unmanaged component with a blank Guid
<Component Id="file.ext" Guid="">
<File .../>
<Component>
and I also changed another component's file location and Id (but not it's Guid). All components present in earlier revisions show PreviouslyPinned=1 and won't uninstall, and new components added after this revision install/uninstall correctly.
How can I get my installer back to normal and remove these previously pinned components?
发布评论
评论(4)
Windows Installer 实际上支持空白 GUID 的概念。它的意思是“安装,但不注册组件”: http://msdn.microsoft.com/en-us/library/aa368007(VS.85).aspx(ComponentId 条目解释了使用 null GUID 时会发生什么情况)。
我刚刚使用 WIX 进行了测试,它似乎遵循空白 GUID 条目(即没有自动生成 GUID)。请记住绝对路径/密钥路径和GUID之间的1:1规则:
总之,GUID 引用对组件的安装密钥路径进行计数,而不是对文件进行计数 - 文件可能会移动,但随后文件通过新的 GUID 具有新标识(想想不同文件夹中具有相同名称的两个文件 - 它们是不同的)文件,不同的身份)。
清理混乱的 GUID 引用计数可能有点混乱。我发现如果我可以更改文件名,就可以有效地解决问题。我还生成了一个新的 guid,从而断开了旧 guid 引用计数的链接。您还可以重命名安装文件夹(理想情况下,这意味着所有组件 GUID 也应该更改)。 RemoveFile 表概念可用于在安装和/或卸载时删除尚未注册为组件的文件(例如生成的文件)。
更新(2018 年 8 月):只是想补充一点,如果您的应用程序依赖于 LoadLibrary / LoadLibraryEx 或“硬代码”文件名的任何类似构造 - 即被加载 - 位于源代码深处。
Windows Installer actually supports the concept of a blank GUID. It means "install, but don't register the component": http://msdn.microsoft.com/en-us/library/aa368007(VS.85).aspx (ComponentId entry explains what happens with a null GUID).
I just tested with WIX and it appears to respect a blank GUID entry (i.e. no guid is auto-generated). Remember the 1:1 rule between absolute path / key path and GUID:
In summary, the GUID reference-counts the component's install key path, not the file - which may move, but then the file has a new identity via a new GUID (think of two files with the same name in different folders - they are different files, different identities).
Cleaning up messed up GUID reference counting can be a bit messy. I find that if I can change the file name that effectively removes the problem. I also generate a new guid and hence break the link to old guid's ref count. You can also rename the installation folder (which would ideally mean that all component GUIDs should be changed as well). The RemoveFile table concept can be used to remove files on install and / or uninstall that have not been registered as components (for example generated files).
UPDATE (Aug, 2018): Just want to add that you should be careful renaming your dlls or exe files if your application relies on LoadLibrary / LoadLibraryEx or whatever similar constructs that "hard code" file names - that are to be loaded - deep in the source code.
更改组件的 id 并使用有效的 GUID 应该可以解决问题。
Changing the id of the component and using a valid GUID should make things right.
简短的回答是:
是的,使用没有 GUID 的 MSI 组件是一种批量复制方法。复制并忘记。
当然,您必须添加一件事:在每次过度安装或卸载(条件“重新安装或修补或删除”)或主要升级之前删除所有文件。
如果没有这一点,它就没有意义。
您可以在自定义操作中执行此操作,甚至可以使用 CMD.exe /c RD /S /Q ....
(当然,自定义代码比这更优雅)
如果你做得正确,你可以设法进行非常简单的设置,而无需 MSI 通常具有的所有陷阱。
当然,如果您逐个文件地递归删除整个目录,那就更容易了。
还没有尝试过,但我会:拥有没有 GUID 的“动态”组件和普通组件,然后提供补丁。从理论上讲,这应该可行,并且对于由于补丁之间的文件集变化很大而导致的许多补丁问题,这将是一个很好的解决方法。
The short answer is:
Yes, using MSI components without GUIDs is kind of a batch copy method. Copy and forget.
Of course you have to add one single thing: Removing all files before every overinstall or uninstall(condition "REINSTALL or PATCH or REMOVE") or Major Upgrade.
Without that, it does not really make sense.
You can do that in a custom action, even with CMD.exe /c RD /S /Q ....
(Of course, custom code is more elegant than this)
If you do it right, you can manage to have quite simple setups without all the traps, MSI normally have.
Of course it is easier, if you remove recursively a whole directory that file-by-file.
Have not tried yet, but I will: Having "dynamic" components without GUID and normal components and then providing a patch. Theoretically this should work and this would be a good workaround for a number of patching problems resulting of highly changing file sets between patches.
1.
事实上,没有 GUID 的组件是真正的“动态文件链接”方法,经常被一些工具或个人错误地称赞。
其他“方式”:
2. 自动生成 GUID 只是一个自动化步骤(当然,这是每个良好设置构建基础架构的一部分:-)
在我看来,这不是动态的,因为如果你动态地制作它,你就会做错:
2a。每次生成完全随机的 GUID
=>错误的算法
2b.仅在第一次创建组件时生成 GUID,并对要打包到新组件中的新资源实现智能“差异”识别
=>唯一有效的文件树同步方法。但你在这里可能会做很多错事......
这是给专家的。
1.
In fact, components without GUIDs are the real "dynamic-file-linking" method often wrongly acclaimed by several tools or persons.
Other "ways":
2. Generating GUIDs automatically is just an automation step (but of course part of every good setup build infrastructure :-)
In my eyes this is not dynamically, because if you make it dynamically, you do it wrong:
2a. Generating GUIDs which are completely random each time
=> wrong algorithm
2b. Generating GUIDs only the first time a component is created and having implemented intelligent "diff" recognition for new resources to be packed in a new component
=> The only working file-tree-sync method. But you can do much wrong here...
It's for experts.