WiX default REFERENCED value OR Registry Value - wix

I need to set a default database file for my application. I only want it to be set on initial installation. If the registry value--a string of the path to the sdf file--changes, then future upgrades should not try to set the value back to the default.
Another caveat, that seems to be a problem, though, is that if they've never setup a database file, the user should be able to use the program with a default database without having to go through setup.
So I set the DATABASEFILE with value="[INSTALLFOLDER]dust.sdf". but candle was complaining that [INSTALLFOLDER]:
The 'DATABASEFILE' Property contains '[INSTALLFOLDER]' 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.
So, following the error's instructions, I added a custom action. Now that custom action ALWAYS overwrites the DATABASEFILE attribute. I want it to only override that value if the value doesn't exist in the registry.
Here's the code:
<CustomAction Id='SetINSTALLFOLDERREF' Property='DATABASEFILE' Value='[INSTALLFOLDER]dust.sdf' Execute='immediate' />
<Property Id='DATABASEFILE' >
<RegistrySearch Id='DatabaseFile' Type='raw' Root='HKCU' Key='Software\DBG\Dust\Database' Name='File'/>
</Property>

Have you set conditions on your custom action with Id=SetINSTALLFOLDERREF? If not, you might want to do it.
A condition of NOT DATABASEFILE on your custom action should probably suffice.
With the above condition,
-In the case of a fresh installation, the registry entry does not exist. Hence, DATABASEFILE is NULL, the custom action condition evaluates to true and the custom action SetINSTALLFOLDERREF executes.
-For any subsequent maintenance operations, the registry key is present, the property DATABASEFILE will always contain a value, the custom action condition evaluates to FALSE and the custom action will not be triggered.
Another thing you might want to do is to add the property DATABASEFILE to the list of SecureCustomProperties ie. secure the property DATABASEFILE.

Related

how to get property from MSI handler during installation, and pass it to uninstall function

In basic MSI project, I add a property "id" in Installation Designer table,set its default value is 50, when I install the service, I set a new value 48 to this property, and use MsiGetProperty(hMSI, "id", ID, nvSize) to get new value, it works fine. but when I unintall the service, use MsiGetProperty(hMSI, "id", ID, nvSize) once more, I only get the default value 50 instead of new value 48.Why?
How can i get the new value during uninstallation?
Because during installation you modify this property only for this instance of installation. It means, when you launch uninstallation - property will have default (initial) value.
The one way to solve this issue - create Registry entry with actual value of id (HKLM\Software\MySoftware\id=48 for example) and during uninstallation just read it with help of SystemSearch to property id.

how to get the modified value of property after the feature is installed?

I have used a dialog in OnFirstUIBefore() for users to input some information,
and stored them in property USERINF.
However, when I want to retrieve the value of USERINF inputted by user in feature_installed(),
what I get is a default value.
I have added the USERINF to SecureCustomProperties property, but still cannot get the modified value.
How can I fix the problem?
I've always written values like these to the registry, then used appsearch to get them out into the property again.
There is no built in way to persist values like these built into MSI.

How to write setup build date to a property

Update 2: The feature request has been declined, simply because WiX cannot support these "fake" variables cmd.exe offers. So the accepted answer below remains the best solution.
Update: I have issued a feature request for adding preprocessor dynamic environment variable support. As soon as the devs respond, I'll update this thread.
Original Question:
I want to write the date when the setup has been built to a property.
<Property Name="BuildDate" Value="$(env.Date)" />
or
<Property Name="BuildDate" Value="$(sys.Date)" />
throws CNDL0150: "Undefined preprocessor variable" while
<Property Name="BuildDate" Value="[Date]" />
will of course write the string "[Date]" to the MSI property.
How can I achieve this?
Edit: I've tried "Date" in all cases, same result. Also, adding a new environment variable called "BuildDate" and setting it to "%DATE%" removes the compilation error, but the value written to the MSI doesn't resolve to the actual date, instead it yields the string "%DATE%".
You can add a property in you wix project (.wixproj) in your first property group, for example (you can format the date and/or time to your liking):
<Date>$([System.DateTime]::Now.ToString("yyyyMMddhhmm"))</Date>
Then in your configurations property groups add this property in <DefineConstants>, if you have more constants then separate them with semicolon ;:
<DefineConstants>Date=$(Date)</DefineConstants>
Lastly add the MSI Property:
<Property Id="BuildDate" Value="$(var.Date)" />
Try to use all uppercase DATE, like this:
<Property Name="BuildDate" Value="$(env.DATE)" />
UPDATE: My initial guess was not correct - environment variables are case-insensitive when referenced this way.
It seems like it depends on the type of the environment variable. There are standard environment variables, like %TEMP%, %windir%, etc. Those are "static", meaning the value is not calculated each time you reference it.
There are dynamic environment variables, which are calculated each time they are referenced. These include %DATE%, %TIME%, etc. It seems that WiX preprocessor can't work with dynamic variables. You can verify this: put $(env.windir) and it will work, put $(env.time) - and it won't. More info about environment variables can be found here.
I have not verified whether there's a wish in WiX bug database to support this. Feel free to do it yourself.
So, back to your question. You can work around this limitation in the following way:
Create preprocessor extension
Reference the value from that extension instead of addressing environment variable direcly
The sample how to create preprocessor extension can be found here.
Here's a sample of the code which does the job:
public class DateExtension : PreprocessorExtension
{
public override string[] Prefixes
{
get
{
return new[] { "date" };
}
}
public override string GetVariableValue(string prefix, string name)
{
string result = null;
switch (prefix)
{
case "date":
switch (name)
{
case "Now":
result = DateTime.Now.ToShortDateString();
break;
}
break;
}
return result;
}
}
And in your WiX code you can use it in the following way:
<Property Id="BuildDate" Value="$(date.Now)" />
Don't forget to:
pass preprocessor extension DLL to the WiX setup project (-ext path/to/PreprocessorExtension.dll)
add [assembly: AssemblyDefaultWixExtension(typeof(PreprocessorWixExtension))] to the preprocessor extension project
Here is the result I observe in the MSI package:
To set property value from another property use the following syntax:
<SetProperty Id="BuildDate" Value="[Date]" After="InstallInitialize" />

WiX: How to create file name from a property value

I have a working WiX installer that correctly writes properties to certain INI files, which works fine, but I have a need to generate the name of an INI file on the fly, from the computer name, eg.
MACHINE(xxx).INI
where xxx is my computer name.
I have tried all sorts of combinations of properties and I just can't seem to get it working. Can anyone put me right ?
This is my latest attempt that doesn't work:
<Property Id="MACHINEINI" Value="MACHINE([%COMPUTERNAME]).ini" />
...
<IniFile Id="IniPermissions"
Directory="MYDIR"
Action="addLine"
Name="[MACHINEINI]"
Section="[ComputerName]"
Key="Permissions"
Value="TEST" />
I never see the value of MACHINEINI, as the filename that gets created is actually called
[MACHINEINI]
The value it writes in is correct, so I see the contents as follows:
[xxx] Permissions=TEST
(where xxx is my machine name)
I have tried using [ComputerName], [COMPUTERNAME], [%COMPUTERNAME]
When I build the installer, I get the following error:
C:\Source\blah\BLAH.wxs(50) : warning CNDL1077 : The 'MACHINEINI' Pro
perty contains '[COMPUTERNAME]' in its value which is an illegal
reference to an other property. If this value is a string literal,
not a property reference, pl ease ignore this warning. To set a
property with the value of another property, use a CustomAction with
Property and Value attributes.
The underlying Windows Installer table doesn't support this. Note that the FileName column is of type FileName. Only the Formatted type can take a [PROPERTY].
IniFile Table
You could need a custom action to write temporary records to the IniFile table to transform the file name. The advantage versus using a custom action to literally write the INI file is that rollback would be automatically handled for you.
It's not possible to tell you how to do this exactly since I don't know what language you'd want to use to write the custom action.
A simpler approach (from the installers perspective) would be to transform the [KEY] name inside a single INI instead of writing to different INI files.

Conditions within custom actions

I recently separated our company installers in to two features (one enabled and one absent), to allow the user to select both, I've used UI_Mondo GUI to allow selection.
I've managed to get our custom action to work if the feature is selected:
<Custom Action="RestartIISForASPNet4" After="AspnetRegIIS"><![CDATA[(NOT INSTALLED) AND (&WebServiceFeature=3) AND NOT (!WebServiceFeature=3)]]></Custom
I tried but for some reason it's coming up with false (IMO, it can't as in the log the WixUI_InstallMode is set to InstallComplete.
<Custom Action="RestartIISForASPNet4" After="AspnetRegIIS"><![CDATA[((NOT INSTALLED) AND (&WebServiceFeature=3) AND NOT (!WebServiceFeature=3)) OR WixUI_InstallMode = "InstallComplete"]]></Custom>
Anybody have any ideas what I'm missing, it's probably really obvious.
WixUI_InstallMode is a private property. This means it uses its default value during InstallExecuteSequence (when your custom action runs).
A solution is to use custom action to save its value in a public property. You can then use that public property in your condition.
Public properties don't have lowercase letters in their names.