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.
Related
I'm a novice WiX user, converting over several existing installations from a no longer maintained (.MSI-producing) commercial product.
As part of that I'm restructuring the original feature/component arrangements to take advantage of some of the new options WiX has opened up. One of these is adding Conditions at Feature rather than Component level, and as part of that I've tried specifying a conditional Feature like this (demo/test items throughout):
<Feature Id="Feature1" Title="Test Only" Level="0">
<Component Id="C1" Guid="*" Directory="SomeDir">
<File Id="File1" KeyPath="yes" Checksum="yes" Name="Test file.txt" Source="D:\xxx.dat" />
</Component>
<Condition Level="1"><![CDATA[INSTALLTYPE <> 1]]></Condition>
</Feature>
Where INSTALLTYPE is a Property defined at <Product> level and subsequently set to 0, 1 or 2 by the user via a RadioButtonGroup in the UI sequence.
Summarising what I've found after a day or so of trying different options and head-scratching:
With an initial Level=0, set to 1 by the condition (as in the sample above), the Feature is never installed.
With an initial Level=1, set to 0 by the condition, the Feature is installed when the condition is satisfied as long as an = test is used in the condition. If a INSTALLTYPE <> 1 is used, or Not (INSTALLTYPE = 1), the feature is never installed.
If a pre-defined Property (such as INSTALLLEVEL) is used in the test rather than my INSTALLTYPE, everything works correctly/as expected.
If equivalent tests are applied at Component, rather than Feature, level, everything works as expected for all Propertys and test operators.
Something seems to be going wrong with INSTALLTYPE but I can't for the life of me work out what. I've tried firing a VBScript custom action (MsgBox("INSTALLTYPE=" & Session.Property("INSTALLTYPE"))) in the Execute sequence to check the value of the Property, and as far as I can see this does display the value I'd expect it to have from the UI setting.
In principle I could get Features installing the way I want using the subset of settings I've found to work (e.g. INSTALLTYPE = 0 OR INSTALLTYPE = 2 rather than INSTALLTYPE <> 1), but my bafflement over apparently simple things not behaving as expected suggests I'm missing something fundamental...so I'm wary of just shrugging and applying workarounds.
If anyone has any thoughts on what I might be doing wrong with the items above, I'd be very happy to hear them!
I am facing issue for RegistrySearch for multistring, where as string search working fine.
Checked in installation logs
Action start 13:40:07: AppSearch. MSI (s) (40:E0) [13:40:07:381]:
PROPERTY CHANGE: Adding MYKEY property. Its value is ''. MSI (s)
(40:E0) [13:40:07:381]: PROPERTY CHANGE: Adding MYSERVICE property.
Its value is 'myvalue2'.
I have trimmed some logs here
Action ended 13:40:51:
ScheduleReboot. Return value 1. Action ended 13:40:51: INSTALL. Return
value 1. You must restart your system for the configuration changes
made to XXXXX to take effect. Click Yes to restart now or No if you
plan to manually restart later. Property(S): UpgradeCode =
{XXXXXX-XXXX-XXX-XXXX-XXXXXXXX}
Property(S): MYKEY = [~]myvalue1[~] Property(S): MYSERVICE = myvalue2
At end of installation it seems it has correctly evaluated the MYKEY but not during AppSearch, resulting in failing my Condition evaluation
<Feature Id="MyFeature" Level="" Display="" Title="" Description="" AllowAdvertise="no" ConfigurableDirectory="INSTALLDIR">
<MergeRef Id="MyFeature" Primary="yes"/>
<Condition Level="0">((MsiNTProductType=1) OR
(MYKEY="[~]MyValue[~]") OR
(MYSERVICE="MyService" AND MYKEY=""))</Condition>
</Condition>
</Feature>
<Property Id="MYKEY" Secure="yes">
<RegistrySearch Id="MyKey"
Root="HKLM"
Key="SYSTEM\CurrentControlSet\Services\MyService"
Name="mykey"
Type="raw" />
</Property>
<Property Id="MYSERVICE" Secure="yes">
<RegistrySearch Id="MYSERVICE"
Root="HKLM"
Key="SYSTEM\CurrentControlSet\Services\MyService"
Name="DisplayName"
Type="raw" />
</Property>
UPDATE: I might have missed you stating it already, but when checking whether the property set by the AppSearch search has any assigned value at all using simply PROPERTYNAME as condition, the condition shows up as true - meaning that "something" exists in the property in question, the text is just not displayed.
Is it sufficient to test just for the presence of a value, or do you need to check the specific value of MYKEY? If the mere presence of a value is enough, then you may be able to use this condition:
((MsiNTProductType=1) OR (MYKEY) OR (MYSERVICE="MyService" AND MYKEY=""))
I guess this answer from Rob Mensching from the WiX-users mailing list answers the question with certainty. Multi-string is simply not supported for AppSearch.
There is no need to doubt the accuracy of this since Rob was on the original MSI team. You need to abandon this approach. Sorry to say. Unless the above workaround that I just added could work (check not the value, but if there is a value at all being retrieved from the registry).
A couple of other, potential workarounds:
You could read the multi-string from a custom action. I just verified that it works with a test VBScript - the forbidden MSI tool :-).
Could you search for a file or directory on disk that would signify the same thing you retrieve from the registry with this multi string?
As my motto goes every now and then: let's obsess over this (as opposed to: "careful, we don't want to learn from this" - which is another motto of mine - which tends to be the better option).
It is truly odd, that I can replicate what you state about your log file. I see a CommandLine entry which shows the multi-sting correctly, albeit with several extra null characters (slightly shortened log entry):
CommandLine: NORMALSTRING="sample regular string" MULTISTRING="[~~~]String 1[~~~]String 2[~~~]String 3[~~~]" INSTALLFOLDER="C:\Program Files (x86)\WiX3_GenericTestProject\" TARGETDIR="C:\" ACTION="INSTALL" EXECUTEACTION="INSTALL" ROOTDRIVE="C:\" INSTALLLEVEL="1" SECONDSEQUENCE="1" ADDLOCAL=Empty,Modules,ProductFeature
and also, later in the log file, after InstallFinalize:
Property(S): MULTISTRING = [~]String 1[~]String 2[~]String 3[~]
I really don't understand how that comes about. Somehow the AppSearch must have really set the property in question even if it didn't look like it did - the property just can't be retrieved correctly (or formatted correctly), and hence doesn't work in (feature) conditions either?
Maybe the underlying data model in Windows Installer has stored the retrieved registry multi string value as a BSTR (the abomination of a COM string format which allows embedded nulls and can be compiled and linked without being properly allocated / constructed via SysAllocateString - "burnt child, smells burnt - and all that...").
Anyway, I suppose AppSearch expectes a regular, null-terminated string buffer and interprets the BSTR as such? Hence stumbling on the first null value which is the first character of the data string section of the BSTR (not the length prefix section - the BSTR pointer points 4 bytes into the allocated BSTR memory) and reports an empty string overall? The property values that show up in the log file must have been read directly from the underlying data model by other means? I would assume the MSI Win32 C++ functions? But wouldn't that also be the case for AppSearch? Something is wrong with how this property string - with embedded nulls - is being displayed and used in conditions.
So in summary: maybe the retrieval of the multi string actually works, but the exposed value via Session.Property("PROP") erroneously reads the potential, native BSTR as a null-terminated string buffer and interprets the leading null as the end of the string buffer? Sort of doesn't make sense considering Session.Property is a COM call and should definitely understand a BSTR? Theories like these are never correct, but maybe they can help create some new ideas at least. What seemed like a missing Windows Installer feature, sort of smells like a bug I think. Or as it is in the real world: a technical problem, not easily fixed and hence seen and accepted as a missing feature.
Let me link together your questions on this issue for reference (and a couple of other answers):
RegistryValue Element of type multiString.
Failing condition wix.
Passing multiString values to installer through command-line.
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 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.