1

Hi I am using Wix to create an Installer that has to write a registry value with the path of the file that the installer copies on the user's system. The problem is that the registry entry should be written in this format

file:///C:/Program Files/....

In the Wix code project I have the INSTALLFOLDER Directory Id which points to

C:\Program Files\....

I am really struggling to convert the latter notation into former. I created a Custom Action hoping to set a property so that I can use that. Following is the code

Custom Action (separate DLL for now, can it be inlined?)

 public class CustomActions
    {
        [CustomAction]
        public static ActionResult CustomAction1(Session session)
        {
            session.Log("Begin CustomAction1");
            string origValue = session["INSTALLFOLDER"];
            MessageBox.Show(origValue);
            string retVal = origValue.Replace("\\", "//");
            MessageBox.Show(retVal);
            session["Custom_Prop"] = retVal;
            return ActionResult.Success;
        }
    }

And the Product.wxs

<?xml version="1.0" encoding="UTF-8"?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">

  <Product Id="*" Name="SetupProject1" Language="1033" Version="1.2.0.0" Manufacturer="nik" UpgradeCode="4a74ff86-49a9-4011-9794-e1c18077172f">
    <Package InstallerVersion="200" Compressed="yes" InstallScope="perMachine" />

    <MajorUpgrade DowngradeErrorMessage="A newer version of [ProductName] is already installed." />
    <MediaTemplate />

    <Feature Id="ProductFeature" Title="SetupProject1" Level="1">
      <ComponentGroupRef Id="ProductComponents" />
    </Feature>

    <InstallExecuteSequence>
      <Custom Action='FooAction' Before='InstallFinalize'>NOT Installed</Custom>
    </InstallExecuteSequence>

  </Product>

  <Fragment>
    <CustomAction Id='FooAction' BinaryKey='FooBinary' DllEntry='CustomAction1' Execute='immediate'
                  Return='check'/>

    <Binary Id='FooBinary' SourceFile='MyCustomAction.CA.dll'/>
  </Fragment>


  <Fragment>
    <Directory Id="TARGETDIR" Name="SourceDir">
      <Directory Id="ProgramFilesFolder">
        <Directory Id="INSTALLFOLDER" Name="SetupProject1" />
      </Directory>
    </Directory>
  </Fragment>

  <Fragment>
    <Property Id="Custom_Prop" Value="[ProgramFilesFolder]"></Property>
    <ComponentGroup Id="ProductComponents" Directory="INSTALLFOLDER">
      <!-- TODO: Remove the comments around this Component element and the ComponentRef below in order to add resources to this installer. -->
      <!-- <Component Id="ProductComponent"> -->
      <!-- TODO: Insert files, registry keys, and other resources here. -->
      <!-- </Component> -->
      <Component Id="cmp_Add_Mainfest_To_Registry" Guid="955A3A76-F010-4FCB-BCAF-B297AFD1C05B">

        <RegistryKey Root="HKCU" Key="SOFTWARE\company">

          <RegistryValue Name="LoadBehavior" Value="3" Type="integer" Action="write" />

          <RegistryValue Name="Manifest" Value="[Custom_Prop]" Type="string" Action="write"  KeyPath="yes"/>
        </RegistryKey>
      </Component>
    </ComponentGroup>
  </Fragment>
</Wix>

However when I run this setup the value written in the registry is the literal string [ProgramFolder] and not its evaluation into either C:\ or C:/

Can someone help?

2 Answers 2

7

The reason why my code wasn't working was this line

 <InstallExecuteSequence>
      <Custom Action='FooAction' Before='InstallFinalize'>NOT Installed</Custom>
    </InstallExecuteSequence>

On changing the value of Before attribute as below made this work

<InstallExecuteSequence>
      <Custom Action='FooAction' Before='CostFinalize'>NOT Installed</Custom>
    </InstallExecuteSequence>

However given my needs were very simple I decided to not have a separate DLL for CustomAction and instead went ahead with a Custom Action in vbscript within the Wix Project. So now the code looks like

<?xml version="1.0" encoding="UTF-8"?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">

  <Product Id="*" Name="SetupProject1" Language="1033" Version="1.3.1.0" Manufacturer="nik" UpgradeCode="4a74ff86-49a9-4011-9794-e1c18077172f">
    <Package InstallerVersion="200" Compressed="yes" InstallScope="perMachine" />

    <MajorUpgrade DowngradeErrorMessage="A newer version of [ProductName] is already installed." />
    <MediaTemplate />

    <Feature Id="ProductFeature" Title="SetupProject1" Level="1">
      <ComponentGroupRef Id="ProductComponents" />
    </Feature>

     <InstallExecuteSequence>
      <Custom Action="VBScriptCommand" After="CostFinalize">NOT REMOVE</Custom>
    </InstallExecuteSequence>

  </Product>

  <Fragment>


    <CustomAction Id="VBScriptCommand" Script="vbscript">
      <![CDATA[         
    value = Session.Property("INSTALLFOLDER")
    origPath=Session.Property("INSTALLFOLDER")
    If Right(webdir, 1) = "\" Then
      value = Left(value, Len(value) - 1) 
    End If

    Session.Property("SOME_PROPERTY") = Replace(origPath,"\","//")      
  ]]>
    </CustomAction>

   </Fragment>

  <Fragment>
    <Directory Id="TARGETDIR" Name="SourceDir">
      <Directory Id="ProgramFilesFolder">
        <Directory Id="INSTALLFOLDER" Name="SetupProject1" />
      </Directory>
    </Directory>
  </Fragment>

  <Fragment>
    <Property Id="Custom_Prop" Value="[ProgramFilesFolder]"></Property>
    <ComponentGroup Id="ProductComponents" Directory="INSTALLFOLDER">

      <Component Id="cmp_Add_Mainfest_To_Registry" Guid="955A3A76-F010-4FCB-BCAF-B297AFD1C05B">

        <RegistryKey Root="HKCU" Key="SOFTWARE\something">

          <RegistryValue Name="LoadBehavior" Value="3" Type="integer" Action="write" />
          <!--<RegistryValue Name="Manifest" Value="[#FILE_VstoManifest]|vstolocal" Type="string" Action="write" />-->
          <RegistryValue Name="Manifest" Value="file:///[SOME_PROPERTY]" Type="string" Action="write"  KeyPath="yes"/>
        </RegistryKey>
      </Component>
    </ComponentGroup>
  </Fragment>
</Wix>

Perhaps the purists won't like this but why use a Shot gun to kill a fly?

Sign up to request clarification or add additional context in comments.

Comments

1

Nikhil helped me with his answer. My installs all go to subfolders so when I find an old component I need the parent folder for install, so I came here for an answer.
Combined with this get parent I found how to get the parent folder since I have a known fixed install sub path.

    <!-- Set INSTALLFOLDER from SERVERINSTALLFOLDER without the \Server\ -->
    <CustomAction Id="VBScriptInstallFolderFromFoundServer" Script="vbscript">
      <![CDATA[         
        pathvalue = Session.Property("SERVERINSTALLFOLDER")
        if pathvalue <> "" Then
          Session.Property("INSTALLFOLDER") = Left(pathvalue,Len(pathvalue)-Len("\Server\"))
        End If
      ]]>
    </CustomAction>

Combined with Locate Installation directory of another product

    <Property Id="SERVERINSTALLFOLDER">
      <!-- Id="C_SERVER_SERVERHOST.EXE" Guid="{xxx GUID OF my exe component xxx}" -->
      <ComponentSearch Id="ServerComponentSearch" Type="file" Guid="{xxx GUID OF my exe component xxx}">
        <DirectorySearch Id="ServerComponentDirectorySearch" Depth="0" AssignToProperty="yes" />
      </ComponentSearch>
    </Property>

And with Wix remember property pattern storing the INSTALLFOLDER path in registry.
I can now update old, or install new getting the correct install path of previous install as suggestion.
Not quite the answer to the question but as I was lead here to get this, my answer will help others on the same path...
My InstallUISequence and InstallExecuteSequence :

      <!-- Save INSTALLFOLDER parameter to CMDLINE_INSTALLFOLDER -->
      <Custom Action='SaveCmdLineValue' Before='AppSearch' />
      <!-- Set INSTALLFOLDER from SERVERINSTALLFOLDER without the \Server\ -->
      <Custom Action="VBScriptInstallFolderFromFoundServer" After="AppSearch">
        SERVERINSTALLFOLDER
      </Custom>
      <!-- Set INSTALLFOLDER from parameter CMDLINE_INSTALLFOLDER -->
      <Custom Action='SetFromCmdLineValue' After='VBScriptInstallFolderFromFoundServer'>
        CMDLINE_INSTALLFOLDER
      </Custom>

And lastly... in Product I to refer to the Fragment I put these in:

    <!-- Install to previous install path From parameter, OR from found installation OR from registry -->
    <CustomActionRef Id='SaveCmdLineValue' />
    <PropertyRef Id='INSTALLFOLDER'/><!-- include Fragment -->
    <PropertyRef Id='SERVERINSTALLFOLDER'/><!-- include Fragment -->
    <CustomActionRef Id='VBScriptInstallFolderFromFoundServer' /><!-- include Fragment -->

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.