原文:http://robmensching.com/blog/posts/2003/10/18/component-rules-101

I've been debating with myself for the last week whether I really wanted to write this blog entry about the Component Rules. The Windows Installer SDK has some decentdocumentation about what can go wrong when the rules are broken. But right when I had just about decided to write about something more pleasant, on the walk back from lunch yesterday, Robert suggested that I write this entry anyway to put a more emphasis on this topic that has easily sucked up months of my life. Then today there was yet another email thread at work that demonstrated people still don't understand the Component Rules. So, on the drive home tonight when I heard that C89.5 was going to play the entirety of Basement Jaxx's new album Kish Kash, I decided I would sit down and write the blog entry about the Component Rules. So here we are and here we go.

In a previous blog entry I talked about the basics of Windows Installer Components. If you haven't read that entry you should do so before continuing on here. Done? Great, let's continue.

At the end of that previous blog entry, I hinted at a flaw in the way the Windows Installer reference counted Components and the Resources contained in them. Rather than give the answer right away, I'll start building up an example then walk through the problem step by step and we'll see how quickly you can jump to the conclusion.

Note, I'm going to pretend to use a bit of set notation here but I can't find my discrete mathematics book right now so I apologize now if I butcher the syntax.

First, remember that every Component in the Windows Installer has a Globally Unique Identifier (GUID) that I called the ComponentId. Also remember that the Windows Installer tracks (reference counts) Components only by their ComponentIds. I like examples so let's say we have three Components with their ComponentIds like:

 C1 - ComponentId = "{0F794AC3-F266-4238-BC59-4AD641DD5F8F}"  C2 - ComponentId = "{5B2390D5-C8D0-43b0-980F-01A872E809C4}"  C3 - ComponentId = "{0F794AC3-F266-4238-BC59-4AD641DD5F8F}" 

Now to us, it looks like there are three Components listed. However, the Windows Installer would only see two Components because C1 and C3 have the same ComponentId (trust me, I cut'n'pasted them). Okay, so now, let's say I also have three Resources:

 R1 is a Registry Key = "HKLM\Software\Microsoft\Wix\Data=example.wxs"  R2 is a Registry Key = "HKLM\Software\Microsoft\Wix\Version=2.0.0.0"  R3 is a File = "[ProgramFilesFolder]\Wix\candle.exe"

I probably only need two Resources for the example, but electrons are cheap. Anyway, the actual types of Resources listed above don't matter. I just wanted to make the example a little more concrete since I know I don't like it when people start hand waving at abstract concepts.

Now, that we have some Components and Resources, let's run through some simple logical statements. For the rest of this entry, the symbol "==" means "is equivalent to" and the symbol "!=" means "is not equivalent to". Okay? Okay.

 C1 == C1  C1 != C2  C1 == C3  C3 == C1  R1 == R1  R1 != R2  R1 != R3  C1 != R1 (and some people would argue this is a nonsensical thing to do anyway  since Resources aren't Components to begin with and discussing their  equivalency is pointless!) 

All I'm trying to show is that the Components with the same ComponentId are identical and the Resources provided are all unique. Now that we have some building blocks for a setup, let's put them together for our first scenario

 C1 = { R1 }  C2 = { R2, R3 }  C3 = { R1 } 

What I've tried to represent in set notation is that Component 1 contains Resource 1, Component 2 contains Resources 2 and 3, and Component 3 contains Resource 1. Nothing magical here. Again, if we do the equivalency tests on the contents Components the following should all still be true:

 C1 == C1  C1 != C2  C1 == C3  C3 == C1 

But enough truth statements, I'm here to talk about installation. So let's pretend that we had the Windows Installer install each of those three Components on a "clean machine" (a machine that has never had these Components installed before). We're talking about reference counts a lot in this blog entry, so let's take a look at the reference counts on the ComponentIds and Resources after the installation is complete:

[ten after midnight and the DJ has started playing Basement Jaxx, sweet...]

 {0F794AC3-F266-4238-BC59-4AD641DD5F8F} - 2 (C1 and C3)  {5B2390D5-C8D0-43b0-980F-01A872E809C4} - 1 (C2)  R1 - 2  R2 - 1  R3 - 1 

What does this mean? Let me try to represent the lines above in English. "The ComponentId {0F794AC3-F266-4238-BC59-4AD641DD5F8F} has been installed on the machine twice, once by Component 1 and again by Component 3. The Component 2 with its GUID has been installed on the machine once. The Windows Installer only reference counts Components but if we were to apply the reference counts from the Components to their contained Resources we'd notice that Resource 1 has a reference count of two while all the other Resources have a single reference count."

Now let's say we were to uninstall Component 1 and Component 2. The resulting reference counts would look like this:

 {0F794AC3-F266-4238-BC59-4AD641DD5F8F} - 1 (C3)  R1 - 1 

Notice that Component 2 and its Resources are gone. That's because their reference count reached zero and were thus removed from the machine. Component 1 was removed so the count on the ComponentId it shared with Component 3 was reduced by one but did not hit zero so the Component is still there. If we remove Component 3 now then all of our Resources would be removed from the machine.

So far so good, so let's move on and introduce a new scenario with just Components 1 and 2 like thus:

 C1 = { R1 }  C2 = { R1 } 

Now, Resource 1 is installed by two different Components.So if we go back to our clean machine and install each of these Components the resulting reference count on the Components and Resources would look like this:

 {0F794AC3-F266-4238-BC59-4AD641DD5F8F} - 1 (C1)  {5B2390D5-C8D0-43b0-980F-01A872E809C4} - 1 (C2)  R1 - 1 

See the problem? No, that's not a typo. Let's try it in English, "The ComponentId {0F794AC3-F266-4238-BC59-4AD641DD5F8F} has been installed once by Component 1 and the ComponentId {5B2390D5-C8D0-43b0-980F-01A872E809C4} has been installed once by Component 2. The Windows Installer only reference counts Components but if we were to apply the reference counts from the Components to their contained Resources we'd notice that Resource 1 gets a count of one from two different Components. Unfortunately, that isn't additive so the Resource 1 ends up with a reference count of one."

So what happens when you uninstall Component 1 (or Component 2, it doesn't matter)? Yep, you guessed it:

 {5B2390D5-C8D0-43b0-980F-01A872E809C4} - 1 (C2) 

Resource 1 has been removed prematurely from the machine. Yes, this is wrong. Yes, this is the way the Windows Installer really works. Yes, there are variations on the scenario that result in Resources being "orphaned" (left behind) after uninstall and Resources not being installed on the machine when a Component tries to install them.

The thing I find interesting is that if you take the first logical statement about the Windows Installer's view of equivalency between Component 1 and Component 2 and compare that to the mathematical equivalency of the sets that represent Component 1 and Component 2 in the last scenario you get this:

 C1 != C2 where "{0F794AC3-F266-4238-BC59-4AD641DD5F8F}" != "{5B2390D5-C8D0-43b0-980F-01A872E809C4}"  C1 == C2 where { R1 } == { R1 } 

While not quite as profound as Russell's Paradox, if you're using the Windows Installer this design flaw is something you should definitely be aware of when putting Resources in Components. Hopefully, it also demonstrates that you should never put someone else's Resources in one of your Components.

C89.5 has finished playing the new Basement Jaxx CD and I have a flag football game in 8 hours (we have the early game this weekend) so I'm going to wrap this blog entry up here. If people want, I can drill into more detail about the Component Rules in future blog entries. However, I think we have enough information here to understand the problem and provide justification for Merge Modules thus unlocking new branches in my thought tree.

Until next time.

[WiX]Component Rules 101的更多相关文章

  1. Use XSLT in wix

    Following content is directly reprinted from https://installpac.wordpress.com/2012/05/07/conflict-ma ...

  2. wix在使用heat自动生成wxs时添加windows服务组件

    最近需要给安装包增加一个windows服务组件,按照我的理解,我以为只需要Product.wxs加一段如下的标签就可以了 <Componet Id="myservice"&g ...

  3. Ngnix反向代理react-router配置问题解决方法

    项目以react router实现,用ngnix做反向代理的时候出现404找不到页面,有两种解决方法. 第一种  将<Route path="*" component={No ...

  4. How to build windows azure PowerShell Source Code

    Download any version source code of Windows Azure Powershell from https://github.com/Azure/azure-sdk ...

  5. CSS架构

    CSS架构 有趣的是,我们通常不这样评判其他语言.一个Rails开发者不会因为他写的代码规范就认为他是一个好的开发者.因为这是最基本的.当然它必须是满 足规范,除此以外还要考虑其他方面:代码是否有可读 ...

  6. Paying for upgrades, by Bob Arnson

    Following content is reprinted from here, please go to the original website for more information. Au ...

  7. CSS架构目标

    擅长CSS的Web开发人员不仅可以从视觉上复制实物原型,还可以用代码进行完美的呈现.无需使用表格.尽可能少的使用图片.如果你是个名副其实的高手,你可以快速把最新和最伟大的技术应用到你的项目中,比如媒体 ...

  8. Sonar Java 规则插件开发 (基于阿里开发手册)

    引言 最近在做Sonar静态代码扫描管理,以此顺手接了Sonar的插件开发,基于阿里开发手册进行开发,在整体开发过程中,其中还是遇到不少坑位,也以此给大家做相应借鉴官网Demo演示插件开发地址:htt ...

  9. Eclipse集成SonarLint

    https://docs.sonarqube.org/display/PLUG/Writing+Custom+Java+Rules+101

随机推荐

  1. redis学习-有序集合(zset)常用命令

    zadd:有序集合增加一个或者多个键值对 与set集合不同,zset添加的时候需要 指定 score,这个是用来排名的 zrange:返回指定范围的键 zcount:返回集合指定范围的个数(以每个键值 ...

  2. Python全栈2期 备忘

    http://www.cnblogs.com/linhaifeng/ http://www.cnblogs.com/alex3714/ http://www.cnblogs.com/wupeiqi/ ...

  3. UVa 10881 Piotr's Ants (等价变换)

    题意:一个长度为L的木棍上有n个蚂蚁,每只蚂蚁要么向左,要么向右,速度为1,当两只蚂蚁相撞时, 它们同时掉头.给定每只蚂蚁初始位置和朝向,问T秒后,每只蚂蚁的状态. 析:刚看到这个题时,一点思路也没有 ...

  4. cmake-mark_as_advanced

    mark_as_advanced: Mark cmake cached variables as advanced. mark_as_advanced([CLEAR|FORCE] VAR VAR2 V ...

  5. 为Quartus工程生成rbf文件的方法

    rbf文件是Quartus编译生成的fpga配置文件的二进制数据量格式的文件,主要用于使用外部主机通过PS方式配置FPGA. 在含ARM硬核的SoC FPGA中,可以使用HPS配置FPGA,配置时分为 ...

  6. NC入门笔记

    简介: NC(全名NetCat),在网络界有"瑞士军刀"的美誉.它小巧而强悍,被设计成一个稳定的后门工具,能够直接由其它程序和脚本轻松驱动.同时,它也是一个功能强大的网络调试和探测 ...

  7. hdu 5046 二分+DLX模板

    http://acm.hdu.edu.cn/showproblem.php?pid=5046 n城市建k机场使得,是每个城市最近机场的距离的最大值最小化 二分+DLX 模板题 #include < ...

  8. Create a site by Google Site - All Free

    Follow this link :  https://www.google.com/sites/help/intl/en/overview.html

  9. queued frame 造成图形性能卡顿

    曾经遇到过卡顿是类似的原因:当时对显卡底层知识理解不懂,看到引擎底层有一个MaxFramexxx的接口,实现是使用注册表修改显卡底层的注册信息,当时还是一个掉接口习惯的客户端码农的思维,没理解底层含义 ...

  10. Python学习-40.Python中的迭代

    在上一篇中,我们使用了生成器来创建了一个可遍历的对象.在其中,我们使用了yield关键字. Python我也正在学习中,因此对yield的本质我并不熟悉,但是,在C#中,yield关键字则是语法糖,其 ...