Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

WiX DirectorySearch/@Depth is ignored if used more than once in the same tree

I have a WiX installer that install a bunch of extension files to the app directory for another app. To ensure that the files end up in the right place, I use a bunch of nested DirectorySearch to find the app directory.

The app is usually installed in a path following this pattern:

\Program Files (x86)\CompanyName\ProductName\[version]\[environment]\[optional intermediate folder]\AppFolderName

In other words, common installation folders include:

\Program Files (x86)\CompanyName\ProductName\1.0\Prod\AppFolderName
\Program Files (x86)\CompanyName\ProductName\1.1\Prod\OptionalFolderName\AppFolderName
\Program Files (x86)\CompanyName\ProductName\1.2\Test\AppFolderName
\Program Files (x86)\CompanyName\ProductName\1.2\Test\OptionalFolderName\AppFolderName

To handle this, I'm using a nested set of DirectorySearch elements to assign the path to a Property. The following works if the optional folder (OptionalFolderName) is present:

<Property Id="SOMEAPPFOLDER">
  <DirectorySearch Id="ProgramFilesFolder" Path="[ProgramFilesFolder]">
    <DirectorySearch Id="CompanyNameFolder" Path="CompanyName">
      <DirectorySearch Id="ProductFolder" Path="ProductName">
          <DirectorySearch Id="EnvironmentFolder" Path="$(var.ENVIRONMENTNAME)" Depth="2">
            <DirectorySearch Id="OptionalIntermediateFolder" Path="OptionalFolderName">
              <DirectorySearch Id="AppFolder" Path="AppFolderName" AssignToProperty="yes">
                <FileSearch Id="AppNameExe" Name="AppName.exe" MinVersion="$(var.MIN_VERSION).0" MaxVersion="$(var.MAX_VERSION).999" />
              </DirectorySearch>
            </DirectorySearch>
        </DirectorySearch>
      </DirectorySearch>
    </DirectorySearch>
  </DirectorySearch>
</Property>

However, since OptionalFolderName is optional, I want to use a DirectorySearch to determine if the app folder is directly under the environment folder or one level down. In an attempt to do this, I changed the search tree to:

<Property Id="SOMEAPPFOLDER">
  <DirectorySearch Id="ProgramFilesFolder" Path="[ProgramFilesFolder]">
    <DirectorySearch Id="CompanyNameFolder" Path="CompanyName">
      <DirectorySearch Id="ProductFolder" Path="ProductName">
        <DirectorySearch Id="EnvironmentFolder" Path="$(var.ENVIRONMENTNAME)" Depth="2">
          <DirectorySearch Id="AppFolder" Path="AppFolderName" Depth="2" AssignToProperty="yes">
            <FileSearch Id="AppNameExe" Name="AppName.exe" MinVersion="$(var.MIN_VERSION).0" MaxVersion="$(var.MAX_VERSION).999" />
          </DirectorySearch>
        </DirectorySearch>
      </DirectorySearch>
    </DirectorySearch>
  </DirectorySearch>
</Property>

The later version however does not work if the optional folder is present, but it does work if it is not present. In other words, it is as if one of the the Depth attributes is isgnored; my guess is that this is because I am using the Depth attribute twice at different levels within the tree.

Any suggestions on how I can work around this?


Update - added log snippet extract from msiexec /i [msiname] /l*v [logfile]:

Action 14:38:47: AppSearch. Searching for installed applications
Action start 14:38:47: AppSearch.
AppSearch: Property: SOMEAPPFOLDER, Signature: AppFolder
MSI (c) (00:90) [14:38:47:065]: Note: 1: 1322 2:  
MSI (c) (00:90) [14:38:47:065]: Note: 1: 1322 2:  
MSI (c) (00:90) [14:38:47:065]: Note: 1: 1324 2: [environmentname] 3: 1 
MSI (c) (00:90) [14:38:47:065]: Note: 1: 1325 2: CompanyName 
Action ended 14:38:47: AppSearch. Return value 1.
MSI (c) (00:90) [14:38:47:066]: Doing action: LaunchConditions
MSI (c) (00:90) [14:38:47:067]: Note: 1: 2205 2:  3: ActionText 
Action 14:38:47: LaunchConditions. Evaluating launch conditions
Action start 14:38:47: LaunchConditions.
MSI (c) (00:A8) [14:38:47:069]: Font created.  Charset: Req=0, Ret=0, Font: Req=MS Shell Dlg, Ret=MS Shell Dlg

Couldn't find the AppFolderName app folder for [environment/version].
MSI (c) (00:90) [14:38:48:543]: Note: 1: 2205 2:  3: Error 
MSI (c) (00:90) [14:38:48:543]: Note: 1: 2228 2:  3: Error 4: SELECT `Message` FROM `Error` WHERE `Error` = 1709 
MSI (c) (00:90) [14:38:48:543]: Product: [productname] -- Couldn't find the AppFolderName app folder for [environment/version].

Action ended 14:38:48: LaunchConditions. Return value 3.
like image 935
KristoferA Avatar asked Sep 20 '13 05:09

KristoferA


2 Answers

Behavior of Depth when FileSearch is used

Depth works differently when FileSearch is an immediate descendant of DirectorySearch.

In the normal case, Depth specifies the maximum number of folder levels above the specified path. However, if FileSearch is an immediate descendant, Depth specifies the maximum number of folder levels to look for the file below the specified path.

In other words, there's no way to specify the depth for a directory that is an immediate parent of a file.

Example

Let's look at the code you've pasted:

<Property Id="SOMEAPPFOLDER">
  <DirectorySearch Id="ProgramFilesFolder" Path="[ProgramFilesFolder]">
    <DirectorySearch Id="CompanyNameFolder" Path="CompanyName">
      <DirectorySearch Id="ProductFolder" Path="ProductName">
        <DirectorySearch Id="EnvironmentFolder" Path="$(var.ENVIRONMENTNAME)" Depth="2">
          <DirectorySearch Id="AppFolder" Path="AppFolderName" Depth="2" AssignToProperty="yes">
            <FileSearch Id="AppNameExe" Name="AppName.exe" MinVersion="$(var.MIN_VERSION).0" MaxVersion="$(var.MAX_VERSION).999" />
          </DirectorySearch>
        </DirectorySearch>
      </DirectorySearch>
    </DirectorySearch>
  </DirectorySearch>
</Property>

In the above, the first use of Depth allows two directory levels between ProductFolder and EnvironmentFolder, but the second use of Depth refers to the number of levels between AppFolder and AppNameExe.

Workaround

The following xml uses two searches to workaround the problem:

<!-- Locate the parent directory first -->
<Property Id="SOMEAPPFOLDER">
  <DirectorySearch Id="ProgramFilesFolder" Path="[ProgramFilesFolder]">
    <DirectorySearch Id="CompanyNameFolder" Path="CompanyName">
      <DirectorySearch Id="ProductFolder" Path="ProductName">
        <DirectorySearch Id="EnvironmentFolder" Path="$(var.ENVIRONMENTNAME)" Depth="1">
          <DirectorySearch Id="AppFolder" Path="AppFolderName" Depth="1" />
        </DirectorySearch>
      </DirectorySearch>
    </DirectorySearch>
  </DirectorySearch>
</Property>

<!-- Now, look for the file in the above directory -->
<Property Id="APPFILEEXISTS">
  <DirectorySearch Id="AppFolder" Path="SOMEAPPFOLDER">
    <FileSearch Id="AppNameExe" Name="AppName.exe" MinVersion="$(var.MIN_VERSION).0"
      MaxVersion="$(var.MAX_VERSION).999" />
  </DirectorySearch>
</Property>
like image 59
AbdullahC Avatar answered Nov 15 '22 10:11

AbdullahC


The second depth is used to search the file two levels below AppFolder, not to search AppFolder two levels below EnvironmentFolder.

You can do a first folder search:

<Property Id="SOMEAPPFOLDER">
  <DirectorySearch Id="ProgramFilesFolder" Path="[ProgramFilesFolder]">
    <DirectorySearch Id="CompanyNameFolder" Path="CompanyName">
      <DirectorySearch Id="ProductFolder" Path="ProductName">
        <DirectorySearch Id="EnvironmentFolder" Path="$(var.ENVIRONMENTNAME)" Depth="2">
          <DirectorySearch Id="AppFolder" Path="AppFolderName" Depth="2" AssignToProperty="yes">
           <!-- <FileSearch Id="AppNameExe" Name="AppName.exe" MinVersion="$(var.MIN_VERSION).0" MaxVersion="$(var.MAX_VERSION).999" /> -->
          </DirectorySearch>
        </DirectorySearch>
      </DirectorySearch>
    </DirectorySearch>
  </DirectorySearch>
</Property>

And use it as reference to verify that the app file exists:

<Property Id="APPEXISTS">
  <DirectorySearchRef Id="AppFolder" Parent="EnvironmentFolder" Path="AppFolderName">
     <FileSearch Id="AppNameExe" Name="AppName.exe" MinVersion="$(var.MIN_VERSION).0" MaxVersion="$(var.MAX_VERSION).999" />
  </DirectorySearchRef>
</Property>
like image 23
Juan Mellado Avatar answered Nov 15 '22 10:11

Juan Mellado