Alex Shevchuk

Always listen to experts. They’ll tell you what can’t be done, and why. Then do it. - Lazarus Long

Is it possible to use RegistrySearch result in RegistryValue?

Is it possible to use RegistrySearch result in RegistryValue?

  • Comments 2
  • Likes

Русская версия здесь.

 

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="http://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.

 

Attachment: SetRegistry1.zip
Comments
  • Alex, useful post but could you explain the prepending .. bit, I am not sure what this was for.

  • 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

Your comment has been posted.   Close
Thank you, your comment requires moderation so it may take a while to appear.   Close
Leave a Comment