0

I have a Wix set up project, and I am trying to figure out a way to not be including every dependency manually as I have to it to a bunch of different projects.

I'm trying to use a batch file on pre-build, which looks like

@echo off
set TARGETDIRECTORY=%1
set OUTPUTFILE=%2
set PROJDIR=%3
echo Starting Dependency check...
echo ^<?xml version="1.0" encoding="UTF-8"?^> > %OUTPUTFILE%
echo ^<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi"^> >> %OUTPUTFILE%
echo   ^<Fragment^> >> %OUTPUTFILE%
echo     ^<ComponentGroup Id="MyWebApiBinaries" Directory="INSTALLFOLDER"^> >> %OUTPUTFILE%

for %%F in (%TARGETDIRECTORY%\*.dll) do (
    echo "-- Adding %%~nxF" 
    echo "-- Calling %PROJDIR%Uuidgen.Exe"
    %PROJDIR%Uuidgen.Exe> %PROJDIR%temp.txt
    set /p aGUID=<%PROJDIR%temp.txt
    del %PROJDIR%temp.txt
    echo "-- Adding %aGUID%"
    echo       ^<Component Id="%%~nxF" Guid="%aGUID%"^> >> %OUTPUTFILE%
    echo                     ^<File  Id="%%~nxF" Name="%%~nxF" Source="%%~dpnxF" Vital="yes" KeyPath="yes" DiskId="1"/^> >> %OUTPUTFILE%
    echo       ^</Component^> >> %OUTPUTFILE%
)

echo     ^</ComponentGroup^> >> %OUTPUTFILE%
echo   ^</Fragment^> >> %OUTPUTFILE%
echo ^</Wix^> >> %OUTPUTFILE%
echo Dependency check done.

Got this idea from this answer except that I needed to add a GUID because I'm installing on inetpub instead of Program Files. So I've included uuidgen.exe into the project to generate a GUID. I call the exe and echo the guid into a temp file, which I later tried to read from, except that it doesn't read it. I've tried this approach on a different batch file and manually calling it and it does read it, so I don't know why it doesn't work here. Basically I'm talking about these two lines:

%PROJDIR%Uuidgen.Exe> %PROJDIR%temp.txt
set /p aGUID=<%PROJDIR%temp.txt

I've remove the delete to check that the file is generating the guid and being created, and it is there, so I know it would have to be the second line.

I've also tried running

for /f %%i in ('"%PROJDIR%\Uuidgen.Exe"') do set GUID=%%i

instead of the other two lines, but I don't get the guid on the variable

I know it doesn't get there because I added an echo with the variable, and also %OUTPUTFILE% is being generated with an Guid="" (just an empty string/variable). Any ideas why it wouldn't get the guid on the variable?

Community
  • 1
  • 1
CPay
  • 47
  • 6
  • `Delayed expansion` issue. I've include an answer about how to solve this without enabling it. But you must pay close attension to other posts, as `delayed expansion` or `variable expansion within a block` have been asked tons of times. Hope it helps. – elzooilogico Jan 05 '17 at 12:10
  • Why can't you just use auto generated GUIDs by either omitting the guid attribute or using `Guid="*"`? If you ever auto generate a wxs file for the same components again you may run into issues when upgrading depending on where you schedule removeexistingproducts – Brian Sutherland Jan 05 '17 at 14:55
  • @Brian Sutherland, because outer wise it would error out, i think automatically generated guids only works on programfiles folder. But your concern is valid as well, I hadn't thought about that scenario – CPay Jan 05 '17 at 17:51

1 Answers1

1

This is our old friend delayed expansion issue.

There are tons of questions about variable expansion within blocks.

When the command processor finds a block (anything between parentheses), parses it completely and expand variables to the value they have when the block is evaluated. If you update a variable value within a block, you need to enable delayed expansion for the variable to reflect changes made. Also you must change var syntax from %var% to !var!.

In your code, aGUID var is generated within a for block, so it's expanded to the value it holds when the block begins (in your case empty or undefined). To update value every iteration of the for block you need to enable delayed expansion.

Another workaround is to use a new for loop to grab output of uuidgen.exe as for variables are always expanded inline. This approach gives you another benefit, you won't need a temp file.

NOTE: Also, you are writing multiple lines to a file, note that

>"%output%" (
   for ... do (
     echo(...
     echo(...
   )
)  

Opens the file only once, whereas

   for ... do (
     echo(...>>"%output%"
     echo(...>>"%output%"
   )

Opens and closes the file any time >>"%output%" redirection is used, so first one speeds up the block.

BTW

>"%output%" (
   for ... do (
     ...
   )
)  

is the same as

(
   for ... do (
     ...
   )
)>"%output%"  

Finally, its best practice enclose within quotes both var name and var content as in

set "TARGETDIRECTORY=%~1"

to get rid of undesired trailing spaces, also %~1 means first argument without quotes.

Not tested. Posible working code

@echo off
SetLocal

set "TARGETDIRECTORY=%~1"
set "OUTPUTFILE=%~2"
set "PROJDIR=%~3"

if not "%TARGETDIRECTORY%" EQU "" if not "%OUTPUTFILE%" EQU "" echo Missing argument/s.& exit/B
if not exist "%PROJDIR%Uuidgen.Exe" echo Uuidgen.exe not found or missing argument.& exit/B

echo Starting Dependency check...

>"%OUTPUTFILE%" (
  echo ^<?xml version="1.0" encoding="UTF-8"?^>
  echo ^<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi"^>
  echo   ^<Fragment^>
  echo     ^<ComponentGroup Id="MyWebApiBinaries" Directory="INSTALLFOLDER"^>

  for %%F in (%TARGETDIRECTORY%\*.dll) do (
      for /F %%U in ('"%PROJDIR%Uuidgen.Exe"') do (
         echo "-- Adding %%~nxF - GUID %%U" >CON
         echo       ^<Component Id="%%~nxF" Guid="%%U"^>
         echo                     ^<File  Id="%%~nxF" Name="%%~nxF" Source="%%~dpnxF" Vital="yes" KeyPath="yes" DiskId="1"/^>
         echo       ^</Component^>
      )   
  )

  echo     ^</ComponentGroup^>
  echo   ^</Fragment^>
  echo ^</Wix^>
)

echo Dependency check done.
EndLocal
exit /B

As all output is redirected to OUTPUTFILE, any message you want to be displayed must be then redirected to standard output >CON, that's why echo "-- Adding %%~nxF - GUID %%U" >CON

elzooilogico
  • 1,659
  • 2
  • 17
  • 18