I have 3 features in my wix-project. When the user choose feature1 or feature2 I need to install the copmonent1. And in case the user choose the feature3 i need to install component2. I realized this with code likes following:
<Component Id="component1" GUID="">
<Condition><![CDATA[(&feature1=3) Or (&feature2=3)]]></Condition>
<RegistryKey Action="createAndRemoveOnUninstall" ...
...
</Component>
<Component Id="component2" GUID="">
<Condition><![CDATA[(&feature3=3)]]></Condition>
<RegistryKey Action="createAndRemoveOnUninstall" ...
...
</Component>
I can't just make two references to component1 from features 1 and 2. Because when user will choose the features 1 and 3 i need to install just second component and not to install the first.
I can't understand, is my condition string wrong? Because after installing the product there is no any registry entry from chosen component. Best regards..
Feature states in component conditions won't work. See http://www.joyofsetup.com/2008/04/09/feature-states-in-component-conditions/ for details.
This is usually done through FeatureComponents table:
component1 can be added in Feature1 and Feature2
component2 can be added in Feature3
I didn't find information about how Wix handles this table, so I'm not sure if you have direct support for it.
Related
Basically i want to add <Condition>0</Condition> element under the <Component>..</Component> element when i harvest a directory using heat.exe
I should look like below
<Component Id='JapaneseFlag' Guid='{4CB0C1EE-8370-4880-B172-CF1E9F7308F7}'>
<File Id='JaFlag' Source='.\ja.png'></File>
<Condition>INSTALLEDSWVERSION = "XYZ"</Condition>
</Component>
and i also want the conditional feature for the above component under the feature element, like
<Feature Id='JA_Flag' Title='Japanese Flag' Level='1'>
<Condition Level='0'>NOT (INSTALLEDSWVERSION = "XYZ")</Condition>
<ComponentRef Id='JapaneseFlag'/>
</Feature>
Is this possible using heat?
if not, So Is there any way to do this dynamically?
Any clue would help me to google further.
Yes, you can use xslt to transform the generated wxs file.
Check this for example.
I had the following "Reg2015" component in RTM in which I forgot to assign KeyPath:
<DirectoryRef Id="INSTALLLOCATION">
<Component Id="Reg2015" Guid="{xxx}" Win64="no" >
<RegistryKey Root="HKLM" Key="SOFTWARE\Mine" >
<RegistryValue Name="RefCount" Value="1" Type="integer" />
<RegistryValue Name="Name" Value="Mine" Type="string" Action="write" />
</RegistryKey>
</Component>
...
</DirectoryRef>
To prepare the patch, I changed "RefCount" to "2" and added to patch wxs.
Now PYRO.EXE complains like this:
error PYRO0243: Component 'Reg2015' has a changed keypath in the transform 'C:\Patch\Patch.Wixmst'. Patches cannot change the keypath of a component.
error PYRO0260: Product '{xxx}': Table 'CreateFolder' has a new row 'INSTALLLOCATION/Reg2015' added. This makes the patch not uninstallable.
I understand since there was no "KeyPath", its KeyPath defaulted to INSTALLLOCATION, but didn't know that component ID was considered as a directory.
(1) Can someone explain why?
(2) Is there any way to pass PYRO errors?
(3) For my next major release, if I add "KeyPath" to any of "RegistryValue" element, like
<RegistryValue Name="RefCount" Value="1" Type="integer" KeyPath="yes" />
should I be able to change "RefCount" to 2 in the future patch?
Thanks.
I think WiX selected Refcount as the keypath for the component - that's what the docs say. " If KeyPath is not set to 'yes' for the Component or for a child Registry value or File, WiX will look at the child elements under the Component in sequential order and try to automatically select one of them as a key path. Allowing WiX to automatically select a key path can be dangerous because adding or removing child elements under the Component can inadvertantly cause the key path to change, which can lead to installation problems. " You could verify that by looking in the MSI file with Orca to see what the Component table says about it.
So changing the keypath value probably resulted in that issue. It would be better to set another registry item (or create a new one) in the component to be the keypath.
I have two msi packages that gets triggered by a bootstrapper and together install a product. I have multiple instance transforms defined for each msi, and I want to set the MultiInstance attribute to 'yes' for all the components in the harvested fragment such that a new component GUID will be generated per instance transform. (It seems that for now, there isn't a heat parameter that you can set to do this, and it has to be accomplished via an xslt transformation.)
I'd want to use -gg flag for Heat to auto-generate static GUIDs because the install directory is set during run-time as a parameter and is not necessarily a standard directory.
Basically, the output should look like:
<Fragment>
<DirectoryRef Id="TARGETDIR">
<Component Id="cmp32EAD7F5A154CBFA668F294AEEE77B45" Guid="{6529235A-EE06-47EB-A56B-1D016B2396CF}" MultiInstance="yes" >
<File Id="fil3F2F6C0F947339E1ED2CF4459569CC5A" KeyPath="yes" Source="$(var.BIN)\File1.txt" />
</Component>
</DirectoryRef>
... Etc.
I'm wondering, even if the GUID is hard-coded such that the linker does not generate it (like above, instead of Guid="*"), will the MultiInstance attribute being set to 'yes' generate unique guids for each instance transforms' components? I sot of became confused about this when I was test calling the MsiGetProductCode by passing in a component guid for a file, which was defined like below:
<Component Id="ProductComponent" Guid="{1C149757-1E1D-424D-AF77-A156CB87F0BF}" MultiInstance="yes">
<!-- TODO: Insert files, registry keys, and other resources here. -->
<File Id="Picture1" Source="C:\Users\Public\Pictures\Sample Pictures\Desert.jpg" ProcessorArchitecture="x64" />
</Component>
* This is a test file that gets installed for all instance transforms defined.
I had two instances from the msi installed (Instance1, Instance2) and the MsiGetProductCode function ran as a part of a custom action that executes during uninstall. On the first execution of MsiGetProductCode, I got the ProductCode of Instance1. On the second execution of MsiGetProductCode (after Instance1 was removed), I got the ProductCode of Instance2. It seemed like that static component id had been used for both instance transforms.
Is the unique component ID generated by the MultiInstance attribute being set to 'yes' not supposed to replace that visible component guid? I haven't had any issues certain files or registry values not being removed due to a component still being used. Basically, I want to confirm that unique guids are being generated per instance and that it's safe to use the MultiInstance attribute to guarantee that component ID collisions will not occur, even when static guids are in use. Could someone kindly elaborate how this works in the background?
Thanks a lot in advance!
It's pretty easy to confirm WiX behavior just by logging the install. Consider the following code:
<Component Id="test" Guid="{EAF11690-2396-4EBE-A74D-37FA1751BBC3}" MultiInstance="yes">
<File Id="test" Source="C:\windows\notepad.exe" KeyPath="yes" />
</Component>
<InstanceTransforms Property="INSTANCEID">
<Instance Id="I01" ProductCode="{7474D99A-B56C-4767-B437-52F56746274A}" ProductName="ProductName2-1" UpgradeCode="{7C2BE622-7543-4F22-A0ED-A9FD28C78C8A}"/>
</InstanceTransforms>
Logging the base and secondary installation reveals that the GUID is unique / transformed.
Another thought would be to extract the instance transform from the MSI and apply it using ORCA to see the differences.
MSI (s) (E4:A4) [10:36:37:021]: Executing op:
ComponentRegister(ComponentId={EAF11690-2396-4EBE-A74D-37FA1751BBC3},KeyPath=C:\Program
Files
(x86)\MyCompany\ProductName2\notepad.exe,State=3,,Disk=1,SharedDllRefCount=0,BinaryType=0)
MSI (s) (E4:DC) [10:37:04:234]: Executing op:
ComponentRegister(ComponentId={BEC4E6A5-9CFB-5C77-A854-CC0179CFEDCE},KeyPath=C:\Program
Files (x86)\My
Company\ProductName2\notepad.exe,State=3,,Disk=1,SharedDllRefCount=0,BinaryType=0)
I have installation of version 1.1. I created upgrade with version 1.2.
In both products I have 2 files:
<Component Win64="yes" Id="cmpFILE1" Guid="*">
<File Id="filFILE1" KeyPath="yes" Source="$(var.BasePathCMP)\Performance.dll" />
</Component>
<Component Win64="yes" Id="cmpFILE2" Guid="*">
<File Id="filFILE2" KeyPath="yes" Source="$(var.BasePathCMP)\LockLib.dll" />
</Component>
During the upgrade LockLib.dll is removed and not being replaced.
In clean installation of 1.2 it is present.
What can cause that behavior?
One of the reasons why this happens is because the action RemoveExistingProducts is being executed after the installation package performed the upgrade. In this case, the MSI detects the file is the same as in previous version and then removes it. You could:
Change order of RemoveExistingProducts
Set the DLL to Shared
I'd recommend option one.
RemoveExistingProducts Element
I'm thinking you changed the component guid for a file that is in both MSIs, older and upgrade. When the RemoveExistingProducts is towards the end of the install the upgrade behaves like a merge, overwriting files if necessary and incrementing ref counts for shared component guids. At the end the REP is removing the old product and decrementing ref counts for the component guids. If there are no more clients for the guid it will be removed. If the guid of a "shared" file changed it will have no more clients and be removed. The thing about an REP at the end is that you must follow component sharing rules, but you don't if you sequence REP at the start of the upgrade.
I'm adding an example for future reference.
Say the first install has 3 files A, B, C, and three guids that are 1, 2 and 3. Your upgrade has the same three files but the guids are 1, 2 and 8. When REP is at the end the upgrade installs over the old product first. Guids 1 and 2 get their ref counts incremented from 1 to 2. Guid 3 stays at 1. Then the older product is uninstalled. Guids 1 and 2 get ref counted down to 1, they are still in use so the files attached to the component guids stay. Guid 3 goes down to zero, has no ref counts so the component is removed, but it's attached to file C so C gets removed even though you just installed it.
What is the best way to write, to a reg key, if a feature was installed during setup?
You should use Component with condition speified. Condition may reference feature states (current or requested - for more details see this link). I use '&' symbol - it gets requested (which should be achieved with installation) feature state.
<Component Id="MyComponentSpecificReg" Guid="YOURGUID">
<Condition>&MyFeatureId = 3</Condition> <!--install this component only of feature requested state is LOCAL (You may need other condition - please read the link I posted above)-->
<RegistryKey Root="YOUR REG ROOT" Key="YOUR REGISTRY PATH" Action="create">
<RegistryValue Name="YourKeyName" Type="string" Value="[YOUR_PROPERTY]"/>
</RegistryKey>
</Component>