Wix Installer - Getting data from a Property - wix

I am using Wix to make an installer and I was wondering how I indirectly get a property's value.
Like if I have a Property WIXUI_INSTALLDIR that is preset with the INSTALLFOLDER value
<Property Id="WIXUI_INSTALLDIR" Value="INSTALLFOLDER" />
and this Property then is changed through a a Dialog from user input and I after that would want to get what the user changed the path to, how do I get the "value" out of WIXUI_INSTALLDIR ?
I would like to send this value (a string I suppose) to either the registry or a custom action.
If I try [WIXUI_INSTALLDIR] I get a warning for illegal indirection if used with a custom action and if I try to send it to registry it just becomes "[WIXUI_INSTALLDIR]" as a string.
EDIT:
My problem is when also using my own made up properties like this:
Property Id="MyOwnProperty" Value="Hello There"
and let's say a Dialogue changes the value of MyOwnProperty, how do I the access the new Value ? Like sending [MyOwnProperty] to a CustomAction as parameter will only get "[MyOwnProperty]" as a literal string.

Try getting the value of the Property (or Directory) that WIXUI_INSTALLDIR references. In this case, use [INSTALLFOLDER] in the formatted field where you'd like the value.

Related

WiX RegistrySearch is failing for MultiString

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.

How to access a property value in MSI within MSM (Merge module)

I'm currently implementing a wix(3.8) installer and the main MSI is merged with several other merge modules. I'm taking a user input during the installation and I store it in a global property called PORT like this.
In the MSI
<Property Id='PORT' Value="1">
I need to access this property value inside a condition in my merge module to edit a XML file if that condition is true. So I passed this property to the merge module as a configuration like this.
In MSI
<ConfigurationData Name="PROTOCOL" Value="[PORT]" />
In MSM
<Property Id="protocol"/>
<Configuration Name="PROTOCOL" Format="Text" DefaultValue="[protocol]"/>
<Substitution Table='CustomAction' Row='SetProtocol' Column='Target' Value='[=PROTOCOL]'/>
<CustomAction Id='SetProtocol' Property='protocol' Value='[protocol]'/>
I used the value of the property "protocol" inside my condition as below but the condition never executes.
<Condition>protocol = 1</Condition>
I tried by appending the property id with the merge module's GUID as well like this and accessing that property "NEWPORT" inside the condition. but didn't success.
<Property Id='NEWPORT' Value='[protocol.8c2910c9-5694-4312-a4cc-c9b2c2a5caa5]'/>
What would be the reason for this ? Can someone please tell me the way to access the property value in MSI within Merge module's condition element.
Thanks in advance.

Custom action to set a property after a failed RegistrySearch is not running

The aim is that if the value isn't found in the registry then I want to assign a default value and then have that value display as the default value in a field in the installer UI. The default value I actually want to use is [ComputerName] but obviously I can't use [ComputerName] directly in the property value attribute because it will give me errors on compiling, specifically:
warning CNDL1077: The 'MYPROPERTY' Property contains '[ComputerName]'
in its value which is an illegal reference to another property. If
this value is a string literal, not a property reference, please
ignore this warning. To set a property with the value of another
property, use a CustomAction with Property and Value attributes.
I want to get it working with plain text before I even try [ComputerName] but so far I can't even get that working.
In my project I have a Product.wxs file which contains the Product element, lots of custom actions (most of which are running fine but they're all running significantly later) and the following elements which are not cooperating and which are all siblings under the Product element.
Property definition and registry search:
<Property Id="MYPROPERTY" Value="ADefaultValue">
<RegistrySearch Id="MyProperty" Type="raw" Root="HKLM" Win64="$(var.Win64)"
Key="Software\MyCompany\MyApplication" Name="MyProperty" />
</Property>
Custom action definition:
<CustomAction Id="SetMyPropertyDefault" Property="MYPROPERTY" Value="MyCustomValue" Execute="immediate"/>
Custom action execution:
<InstallExecuteSequence>
<Custom Action="SetMyPropertyDefault" After="AppSearch"><![CDATA[MYPROPERTY="ADefaultValue"]]></Custom>
</InstallExecuteSequence>
It just will not work for me at all.
For the custom element content I have tried:
<Custom Action="SetMyPropertyDefault" After="AppSearch"><![CDATA[MYPROPERTY="ADefaultValue"]]></Custom>
<Custom Action="SetMyPropertyDefault" After="AppSearch">1</Custom> // I thought this would always run the custom action.
<Custom Action="SetMyPropertyDefault" After="AppSearch">NOT MYPROPERTY</Custom> // Back when I wasn't using the default value on the property at all.
The result is always the same, I'm still getting "ADefaultValue" showing up in the UI, never the alternate "MyCustomValue".
According to every blog and SO post I've seen I'm doing exactly what I should be doing except clearly I'm missing something.
Any ideas?
UPDATE/Answer:
The piece of information that I was missing which was provided by #sutarmin-anton was that InstallUISequence runs before InstallExecuteSequence (seems counter-intuitive to me but there you go).
But as it happened I didn't need to explicitly duplicate the custom action call in each of the install sequence elements, instead I used the SetProperty element.
So now I've got the following in my Product.wxs as children of the Product element:
<Property Id="MYPROPERTY">
<RegistrySearch Id="MyProperty" Type="raw" Root="HKLM" Win64="$(var.Win64)" Key="Software\MyCompany\MyApplication" Name="MyProperty" />
</Property>
<SetProperty Id="MYPROPERTY" After="AppSearch" Value="[ComputerName]">NOT MYPROPERTY</SetProperty>
It now runs the SetProperty after AppSearch in both InstallUISequence and InstallExecuteSequence, but the second time it runs the NOT MYPROPERTY will come out false so it doesn't get reset, and of course if it's run in quiet mode it'll still work correctly.
When you going through installer UI, installation is in InstallUISequence. InstallExecuteSequence runs after all UI events. This is cause of you have not seen "MyCustomValue". To change your property before UI sequence you should place your custom action in "InstallUISequence".
By the way, why don't you set default value of your property to "MyCustomValue"? Then, if AppSearch wont find value in regisrty, it just leave default value that you are trying to set manually.
You may be overcomplicating things. The MYPROPERTY value will not be set at all if you don't set a default. So then you call your CA to set it if 'NOT MYPROPERTY'
I see that you've tried this, and I'd say it's the correct approach that I'd try to diagnose rather than try something else. A verbose log would be invaluable. Do a:
msiexec /i [path to msi] /l*vx [path to a text log file]
and see what CA is called, what AppSearch does, property values etc.
Your original comment of "I can't use [ComputerName] - if that's the problem why not tell us what happened and maybe there is a solution that doesn't require all this. What's the compile error, for example?

Can you assign a WiX Property to CommonAppDataFolder?

I would like to set an overrideable property for a WiX property to the current location of CommonAppDataFolder. So far I have tried the following:
<Property Id="GHOSTSCRIPT" Value="[CommonAppDataFolder]"/>
as well as
<Property Id="GHOSTSCRIPT" Value="CommonAppDataFolder"/>
Neither one resolves correctly. Is there a way to do this?
The Property element writes a row to the Windows Installer Property table. The value column is type "text" not type "formatted" so the [PROPNAME] doesn't work.
The SetProperty element schedules a Property Custom Action (Type 51) in the needed sequence and it supports what you are trying to do.
SetProperty Element

Conditionally set single WiX Property to different values

I have an installer that deploys a website as either a SSL or non-SSL IIS site depending on whether a property is set or not. I've been asked to add the option to set the port, which isn't a problem, but I'd like to set the port to the default values (80 or 443) if the value isn't set.
I tried something like:
<SetProperty Id="OUTPORT" Before="InstallFiles" Value="80"><![CDATA[SSL=0]]></SetProperty>
<SetProperty Id="OUTPORT" Before="InstallFiles" Value="443"><![CDATA[SSL=1]]></SetProperty>
But, obviously, WiX complains about the custom action having the duplicate ID SetOUTPORT.
Am I jumping down another WiX-shaped rabbit hole here?
The accepted answer is not correct in needing to convert to writing out in full the custom action and sequencing (no longer?).
As per documentation for WiX 3, SetProperty Element
Without setting SetProperty\#Action
<SetProperty Id="OUTPORT" Before="InstallFiles" Value="80"><![CDATA[SSL=0]]></SetProperty>
<SetProperty Id="OUTPORT" Before="InstallFiles" Value="443"><![CDATA[SSL=1]]></SetProperty>
Duplicate symbol 'CustomAction:SetInstallFiles' found
Action. String. By default, the action is "Set" + Id attribute's value. This optional attribute can override the action name in the case where multiple SetProperty elements target the same Id (probably with mutually exclusive conditions).
The following works without having to change to writing out custom actions.
<SetProperty Action="SetInstallFiles0" Id="OUTPORT" Before="InstallFiles" Value="80"><![CDATA[SSL=0]]></SetProperty>
<SetProperty Action="SetInstallFiles1" Id="OUTPORT" Before="InstallFiles" Value="443"><![CDATA[SSL=1]]></SetProperty>
It works in WiX 3.7, and I am not sure about which first version it is available from.
SetProperty now supports the Action attribute to let you specify custom action ids when you want to have multiple SetProperty elements for the same property with different conditions.