Is it possible to use RegistrySearch result in RegistryValue?
Русская версия здесь.
This post is an answer to this question sent to wix-users mailing list:
Is it possible to use RegistrySearch result in RegistryValue? Something like this:
<Property Id="PROP1">
<RegistrySearch Id="search1"
Root="HKLM"
Key="somekey"
Name="somename"
Type="raw" />
</Property>
...
<RegistryValue Type="???" Name="othervalue" Value="PROP1" />
First of all, in order to use property, desired field must have Formatted data type. Quick look to Registry table and RegistryValue element reveals that both Value column and Value attribute are in fact Formatted. So, we are good to go. The only change we need to make is to set Value attribute to:
<RegistryValue Type="???" Name="othervalue" Value="[PROP1]" />
Now, how about Type attribute? What value do we need to use?
Description for Registry table is stating that normally the value of Value column is treated as string (REG_SZ) unless it is prefixed with one of the special prefixes or contains the sequence tilde [~]:
Prefix | Meaning |
---|---|
#x | Hexadecimal value (REG_BINARY) |
#% | Expandable string (REG_EXPAND_SZ) |
# | Integer (REG_DWORD) |
Contains [~] | Null-delimited list of strings (REG_MULTI_SZ). |
That means that we should be able to always use Type="string" provided that we properly format values. This fragment successfully proves that:
<SetProperty Id="STRINGPROPCONST" After="AppSearch" Value="QWERTY" />
<SetProperty Id="DWORDPROPCONST" After="AppSearch" Value="#2" />
<SetProperty Id="EXPANDSZPROPCONST" After="AppSearch" Value="#%%SystemRoot%\System32\svchost.exe" />
<SetProperty Id="BINARYPROPCONST" After="AppSearch" Value="#x0123456789ABCDEF" />
<SetProperty Id="MULTISZPROPCONST" After="AppSearch" Value="a[~]b[~]c" />
<Directory Id="TARGETDIR" Name="SourceDir">
<Directory Id="LocalAppDataFolder">
<Directory Id="INSTALLLOCATION" Name="SetRegistry1">
<Component Id="ProductComponent"
Guid="f4ca4e76-d04a-4b89-9a1a-7a666a42a635">
<CreateFolder />
<RemoveFolder Id="RemoveMe" On="uninstall" />
<RegistryKey Id="TestValue"
Root="HKCU"
Key="ACME Corp"
Action="createAndRemoveOnUninstall">
<RegistryValue Id="StringValueConst"
Type="string"
Action="write"
Name="StringPropertyConst"
Value="[STRINGPROPCONST]" />
<RegistryValue Id="DWordValueConst"
Type="string"
Action="write"
Name="DWordPropertyConst"
Value="[DWORDPROPCONST]" />
<RegistryValue Id="ExpandSzValueConst"
Type="string"
Action="write"
Name="ExpandPropertyConst"
Value="[EXPANDSZPROPCONST]" />
<RegistryValue Id="BinaryValueConst"
Type="string"
Action="write"
Name="BinaryPropertyConst"
Value="[BINARYPROPCONST]" />
<RegistryValue Id="MultiSzValueConst"
Type="string"
Action="write"
Name="MultiSzPropertyConst"
Value="[MULTISZPROPCONST]" />
</RegistryKey>
</Component>
</Directory>
</Directory>
</Directory>
So, how we can format data we read from registry during AppSearch? Quick look at RegLocator table reveals that Windows Installer adds a prefix to the registry value that identifies the type of registry value. Cool. Let's test it to see if we already get the value we need:
<Property Id="STRINGPROP">
<RegistrySearch Id="Search1"
Root="HKLM"
Key="SYSTEM\CurrentControlSet\services\wscsvc"
Name="ObjectName"
Type="raw"
Win64="no"/>
</Property>
<Property Id="DWORDPROP">
<RegistrySearch Id="Search2"
Root="HKLM"
Key="SYSTEM\CurrentControlSet\services\wscsvc"
Name="Start"
Type="raw"
Win64="no"/>
</Property>
<Property Id="EXPANDSZPROP">
<RegistrySearch Id="Search3"
Root="HKLM"
Key="SYSTEM\CurrentControlSet\services\wscsvc"
Name="ImagePath"
Type="raw"
Win64="no"/>
</Property>
<Property Id="BINARYPROP">
<RegistrySearch Id="Search4"
Root="HKLM"
Key="SYSTEM\CurrentControlSet\services\wscsvc"
Name="FailureActions"
Type="raw"
Win64="no"/>
</Property>
<Property Id="MULTISZPROP">
<RegistrySearch Id="Search5"
Root="HKLM"
Key="SYSTEM\CurrentControlSet\services\wscsvc"
Name="DependOnService"
Type="raw"
Win64="no"/>
</Property>
<SetProperty Id="STRINGPROPRAW" After="AppSearch" Value="..[STRINGPROP]" />
<SetProperty Id="DWORDPROPRAW" After="AppSearch" Value="..[DWORDPROP]" />
<SetProperty Id="EXPANDSZPROPRAW" After="AppSearch" Value="..[EXPANDSZPROP]" />
<SetProperty Id="BINARYPROPRAW" After="AppSearch" Value="..[BINARYPROP]" />
<SetProperty Id="MULTISZPROPRAW" After="AppSearch" Value="..[MULTISZPROP]" />
<Directory Id="TARGETDIR" Name="SourceDir">
<Directory Id="LocalAppDataFolder">
<Directory Id="INSTALLLOCATION" Name="SetRegistry1">
<Component Id="ProductComponent"
Guid="f4ca4e76-d04a-4b89-9a1a-7a666a42a635">
<CreateFolder />
<RemoveFolder Id="RemoveMe" On="uninstall" />
<RegistryKey Id="TestValue"
Root="HKCU"
Key="ACME Corp"
Action="createAndRemoveOnUninstall">
<RegistryValue Id="StringValueRaw"
Type="string"
Action="write"
Name="StringPropertyRaw"
Value="[STRINGPROPRAW]" />
<RegistryValue Id="DWordValueRaw"
Type="string"
Action="write"
Name="DWordPropertyRaw"
Value="[DWORDPROPRAW]" />
<RegistryValue Id="ExpandSzValueRaw"
Type="string"
Action="write"
Name="ExpandPropertyRaw"
Value="[EXPANDSZPROPRAW]" />
<RegistryValue Id="BinaryValueRaw"
Type="string"
Action="write"
Name="BinaryPropertyRaw"
Value="[BINARYPROPRAW]" />
<RegistryValue Id="MultiSzValueRaw"
Type="string"
Action="write"
Name="MultiSzPropertyRaw"
Value="[MULTISZPROPRAW]" />
</RegistryKey>
</Component>
</Directory>
</Directory>
</Directory>
As you can see, I collected registry values during AppSearch and then used Custom Action Type 51 to set other properties with collected values, but preprended with "..". I did it because I want these values to be interpreted as strings.
It was expected that multi-string value will show up as multi-string, because its interpretation is based on presense of [~] and not on any particular prefix. What is surprising is that expanded string property did show up as expanded and not prefixed with #% whereas description of RegLocator table clearly stating that it should be the case.
So, with the exception of expanded strings, all we need to do is to write values read during AppSearch to registry unchanged:
<?xml version="1.0" encoding="UTF-8"?>
<Wix xmlns="https://schemas.microsoft.com/wix/2006/wi">
<Product Id="30eb65de-f04a-4a79-a153-4542687b7515"
Name="SetRegistry1"
Language="1033"
Version="1.0.0.0"
Manufacturer="SetRegistry1"
UpgradeCode="da268df3-4a01-41de-8c09-a8c11abee160">
<Package InstallerVersion="200" Compressed="yes" InstallScope="perUser" />
<Media Id="1" Cabinet="media1.cab" EmbedCab="yes" />
<Property Id="STRINGPROP">
<RegistrySearch Id="Search1"
Root="HKLM"
Key="SYSTEM\CurrentControlSet\services\wscsvc"
Name="ObjectName"
Type="raw"
Win64="no"/>
</Property>
<Property Id="DWORDPROP">
<RegistrySearch Id="Search2"
Root="HKLM"
Key="SYSTEM\CurrentControlSet\services\wscsvc"
Name="Start"
Type="raw"
Win64="no"/>
</Property>
<Property Id="EXPANDSZPROP">
<RegistrySearch Id="Search3"
Root="HKLM"
Key="SYSTEM\CurrentControlSet\services\wscsvc"
Name="ImagePath"
Type="raw"
Win64="no"/>
</Property>
<Property Id="BINARYPROP">
<RegistrySearch Id="Search4"
Root="HKLM"
Key="SYSTEM\CurrentControlSet\services\wscsvc"
Name="FailureActions"
Type="raw"
Win64="no"/>
</Property>
<Property Id="MULTISZPROP">
<RegistrySearch Id="Search5"
Root="HKLM"
Key="SYSTEM\CurrentControlSet\services\wscsvc"
Name="DependOnService"
Type="raw"
Win64="no"/>
</Property>
<SetProperty Id="STRINGPROPCONST" After="AppSearch" Value="QWERTY" />
<SetProperty Id="DWORDPROPCONST" After="AppSearch" Value="#2" />
<SetProperty Id="EXPANDSZPROPCONST" After="AppSearch" Value="#%%SystemRoot%\System32\svchost.exe" />
<SetProperty Id="BINARYPROPCONST" After="AppSearch" Value="#x0123456789ABCDEF" />
<SetProperty Id="MULTISZPROPCONST" After="AppSearch" Value="a[~]b[~]c" />
<SetProperty Id="STRINGPROPRAW" After="AppSearch" Value="..[STRINGPROP]" />
<SetProperty Id="DWORDPROPRAW" After="AppSearch" Value="..[DWORDPROP]" />
<SetProperty Id="EXPANDSZPROPRAW" After="AppSearch" Value="..[EXPANDSZPROP]" />
<SetProperty Id="BINARYPROPRAW" After="AppSearch" Value="..[BINARYPROP]" />
<SetProperty Id="MULTISZPROPRAW" After="AppSearch" Value="..[MULTISZPROP]" />
<Directory Id="TARGETDIR" Name="SourceDir">
<Directory Id="LocalAppDataFolder">
<Directory Id="INSTALLLOCATION" Name="SetRegistry1">
<Component Id="ProductComponent"
Guid="f4ca4e76-d04a-4b89-9a1a-7a666a42a635">
<CreateFolder />
<RemoveFolder Id="RemoveMe" On="uninstall" />
<RegistryKey Id="TestValue"
Root="HKCU"
Key="ACME Corp"
Action="createAndRemoveOnUninstall">
<RegistryValue Id="StringValueConst"
Type="string"
Action="write"
Name="StringPropertyConst"
Value="[STRINGPROPCONST]" />
<RegistryValue Id="DWordValueConst"
Type="string"
Action="write"
Name="DWordPropertyConst"
Value="[DWORDPROPCONST]" />
<RegistryValue Id="ExpandSzValueConst"
Type="string"
Action="write"
Name="ExpandPropertyConst"
Value="[EXPANDSZPROPCONST]" />
<RegistryValue Id="BinaryValueConst"
Type="string"
Action="write"
Name="BinaryPropertyConst"
Value="[BINARYPROPCONST]" />
<RegistryValue Id="MultiSzValueConst"
Type="string"
Action="write"
Name="MultiSzPropertyConst"
Value="[MULTISZPROPCONST]" />
<RegistryValue Id="StringValueRaw"
Type="string"
Action="write"
Name="StringPropertyRaw"
Value="[STRINGPROPRAW]" />
<RegistryValue Id="DWordValueRaw"
Type="string"
Action="write"
Name="DWordPropertyRaw"
Value="[DWORDPROPRAW]" />
<RegistryValue Id="ExpandSzValueRaw"
Type="string"
Action="write"
Name="ExpandPropertyRaw"
Value="[EXPANDSZPROPRAW]" />
<RegistryValue Id="BinaryValueRaw"
Type="string"
Action="write"
Name="BinaryPropertyRaw"
Value="[BINARYPROPRAW]" />
<RegistryValue Id="MultiSzValueRaw"
Type="string"
Action="write"
Name="MultiSzPropertyRaw"
Value="[MULTISZPROPRAW]" />
<RegistryValue Id="StringValue"
Type="string"
Action="write"
Name="StringProperty"
Value="[STRINGPROP]" />
<RegistryValue Id="DWordValue"
Type="string"
Action="write"
Name="DWordProperty"
Value="[DWORDPROP]" />
<RegistryValue Id="ExpandSzValue"
Type="string"
Action="write"
Name="ExpandProperty"
Value="[EXPANDSZPROP]" />
<RegistryValue Id="BinaryValue"
Type="string"
Action="write"
Name="BinaryProperty"
Value="[BINARYPROP]" />
<RegistryValue Id="MultiSzValue"
Type="string"
Action="write"
Name="MultiSzProperty"
Value="[MULTISZPROP]" />
</RegistryKey>
</Component>
</Directory>
</Directory>
</Directory>
<Feature Id="ProductFeature" Title="SetRegistry1" Level="1">
<ComponentRef Id="ProductComponent" />
</Feature>
</Product>
</Wix>
So, the answer is - Yes, unless we want to preserve expandable string value.
Source code is in attachement.
Comments
Anonymous
May 12, 2009
Alex, useful post but could you explain the prepending .. bit, I am not sure what this was for.Anonymous
May 12, 2009
Sorry, the idea was that to add integer 2 to registry value we need to add prefix '#' to it. So, writing <RegistryValue Type="string" Value="#2" ... /> will actually create registry value of type REG_DWORD with value 2. Description for RegLocator is saying that REG_DWORD value 2 will be represented during AppSearch as string value "#2" in property. Because I wanted to show actual string read from registry during AppSearch, I prepended it with ".." so during writing this value to registry it will be treated as string, not as REG_DWORD. I think, I need to clarify it little bit better. I'll think about it tomorrow. Thanks, Alex