How to specify source location in wix - wix

How do I make the sources specified in a heat generated file visible to the build?
I've got a project named Foo and a project named FooSetup. They have the same parent directory. To generate the list of files to install I ran in FooSetup:
heat dir "..\Foo\bin\Release" -cg "SomeGroupName" -ag -template:fragment -out heat.wxs
Now when I try to build the installer, I get:
The system cannot find the file 'SourceDir\Foo.dll'.
(that file does exist in the Release directory)
The path to Foo\bin\Release is specified in include paths in the FooSetup project properties.
What am I missing here - why is none of the listed files found?

WiX Learning Resources: A couple of links to resources on WiX:
Click-by-click WiX and Visual Studio
Long list of WiX links
WiX Preprocessor Variables: What is SourceDir? Rob Mensching (WiX creator) on SourceDir.
As explained here you can change SourceDir to a compiler variable:
Heat.exe: Something like this:
"%WIX%bin\heat.exe" dir . -sfrag -suid -ag -var MyReleasePath -out MySource.wxs
You will get something like this:
<!-- Extract -->
<Component Id="MyFile.exe" Guid="*">
<File Id="MyFile.exe" KeyPath="yes" Source="$(MyReleasePath)\MyFile.exe" />
</Component>
<!-- End of Extract -->
WiX Sample: Then you insert this into your source. Something like this:
<!-- START OF COMPILER VARIABLES: -->
<?define MyVersion = "1.0.0.0" ?>
<?define MyReleasePath = "C:\My Releases\Wix Testing\" ?>
<!-- END OF COMPILER VARIABLES: -->
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
<Product Id="*" Name="WiX Testing" Language="1033" Version="$(var.MyVersion)"
Manufacturer="WiX Testing" UpgradeCode="PUT-GUID-HERE">
<Package InstallerVersion="200" Compressed="yes" InstallScope="perMachine" />
<MajorUpgrade DowngradeErrorMessage="A newer version of [ProductName] is already installed." />
<!-- Enable line below for GUI in MSI -->
<!-- <UIRef Id="WixUI_Mondo" /> -->
<MediaTemplate EmbedCab="yes" />
<Feature Id="Main" Title="Main Feature" Level="1" />
<Directory Id="TARGETDIR" Name="SourceDir">
<Directory Id="ProgramFilesFolder">
<Directory Id="INSTALLFOLDER" Name="WiX Testing">
<!-- Essential part follows: -->
<Component Feature="Main">
<File Source="$(var.MyReleasePath)MyFile.exe"></File>
</Component>
<!-- End of Essential part -->
</Directory>
</Directory>
</Directory>
</Product>
</Wix>
Batch File Compile: Visual Studio takes care of most of the build issues once you have defined the variables. If you want to compile "manually", here is a quick sample:
"%WIX%bin\candle.exe" MySource.wxs -ext WixUIExtension >> Build.log
"%WIX%bin\light.exe" -out Test.msi MySource.wixobj -ext WixUIExtension >> Build.log
Links:
WiX sample for other issue at bottom

Related

Wix Toolkit 3.11 util namespace fails to load when building

I am trying to build an installer with Wix 3.11.2 in Visual Studio 2019. I have the extension installed and the toolkit.
I want to use the XmlFile tag in the util namespace to modify the app.config of my installed application.
I have added a reference to C:\Program Files (x86)\WiX Toolset v3.11\bin\WixUtilExtension to the installer project.
I have added the util namespace to the Product.wxs
The xmlnamespace is recognized since I get intellisense etc.
However when building I get the error error CNDL0005: The Fragment element contains an unexpected child element 'util:XmlFile'
This is my Product.wxs:
<?xml version="1.0" encoding="UTF-8"?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi"
xmlns:util="http://schemas.microsoft.com/wix/UtilExtension">
<Product Id="DBDA892E-D414-44E9-9F5E-49DCD25E209B" Name="TestWixError" Language="1033" Version="1.0.0.0" Manufacturer="Test" UpgradeCode="41e16593-71c1-4516-8ec3-bc8f4911e3f1">
<Package InstallerVersion="200" Compressed="yes" InstallScope="perMachine" />
<MajorUpgrade DowngradeErrorMessage="A newer version of [ProductName] is already installed." />
<MediaTemplate />
<Feature Id="ProductFeature" Title="TestWixErrorSetup" Level="1">
<ComponentGroupRef Id="ProductComponents" />
</Feature>
</Product>
<Fragment>
<Directory Id="TARGETDIR" Name="SourceDir">
<Directory Id="ProgramFilesFolder">
<Directory Id="INSTALLFOLDER" Name="TestWixErrorSetup" />
</Directory>
</Directory>
</Fragment>
<Fragment>
<ComponentGroup Id="ProductComponents" Directory="INSTALLFOLDER">
<Component Id="MainExecutable" Guid="EA05AA88-F299-4EC2-A64A-4ADAB863C4AC">
<File Id="MainExecutable" Source="$(var.TestWixError.TargetPath)"/>
</Component>
<Component Id="MainPdb" Guid="8ACB76F7-BB83-4EA6-9F58-12CD015E88EC">
<File Source="$(var.TestWixError.TargetDir)$(var.TestWixError.TargetName).pdb" />
</Component>
<Component Id="MainConfig" Guid="39BAFF61-BA1A-42C3-9290-67019F6A6257">
<File Source="$(var.TestWixError.TargetPath).config" />
</Component>
</ComponentGroup>
</Fragment>
<Fragment>
<Property Id="HELLO" Value="Hello from install"/>
<util:XmlFile
Id="UpdateHello"
Action="setValue"
File="$(var.TestWixError.TargetPath).config"
SelectionLanguage="XPath"
Permanent="yes"
ElementPath="/configuration/appSettings/add[\[]#key='Hello'[\] ]/#value"
Value="[HELLO]" />
</Fragment>
</Wix>
The visual studio project is just a .net 4.7.1 console app that displays the value from Hello from the appsettings on the console.
The WixUtilExtension.dll is included in the call to candle.exe as you can see in this commandline (some parts redacted):
C:\Program Files (x86)\WiX Toolset v3.11\bin\candle.exe -dDebug -d"DevEnvDir=C:\Program Files (x86)\Microsoft Visual Studio\2019\Professional\Common7\IDE\\" -d"SolutionDir=C:\Users\---\Documents\Projecten\---\TestWixError\\" -dSolutionExt=.sln -dSolutionFileName=TestWixError.sln -dSolutionName=TestWixError -d"SolutionPath=C:\Users\---\Documents\Projecten\---\TestWixError\TestWixError.sln" -dConfiguration=Debug -dOutDir=bin\Debug\ -dPlatform=x86 -d"ProjectDir=C:\Users\---\Documents\Projecten\---\TestWixError\TestWixErrorSetup\\" -dProjectExt=.wixproj -dProjectFileName=TestWixErrorSetup.wixproj -dProjectName=TestWixErrorSetup -d"ProjectPath=C:\Users\---\Documents\Projecten\---\TestWixError\TestWixErrorSetup\TestWixErrorSetup.wixproj" -d"TargetDir=C:\Users\---\Documents\Projecten\---\TestWixError\TestWixErrorSetup\bin\Debug\\" -dTargetExt=.msi -dTargetFileName=TestWixErrorSetup.msi -dTargetName=TestWixErrorSetup -d"TargetPath=C:\Users\---\Documents\Projecten\---\TestWixError\TestWixErrorSetup\bin\Debug\TestWixErrorSetup.msi" -dTestWixError.Configuration=Debug -d"TestWixError.FullConfiguration=Debug|AnyCPU" -dTestWixError.Platform=AnyCPU -d"TestWixError.ProjectDir=C:\Users\---\Documents\Projecten\---\TestWixError\TestWixError\\" -dTestWixError.ProjectExt=.csproj -dTestWixError.ProjectFileName=TestWixError.csproj -dTestWixError.ProjectName=TestWixError -d"TestWixError.ProjectPath=C:\Users\---\Documents\Projecten\---\TestWixError\TestWixError\TestWixError.csproj" -d"TestWixError.TargetDir=C:\Users\---\Documents\Projecten\---\TestWixError\TestWixError\bin\Debug\\" -dTestWixError.TargetExt=.exe -dTestWixError.TargetFileName=TestWixError.exe -dTestWixError.TargetName=TestWixError -d"TestWixError.TargetPath=C:\Users\---\Documents\Projecten\---\TestWixError\TestWixError\bin\Debug\TestWixError.exe" -out obj\Debug\ -arch x86 -ext "C:\Program Files (x86)\WiX Toolset v3.11\bin\\WixUtilExtension.dll" Product.wxs
Things I have tried so far:
Removing the reference, restarting visual studio re-adding the reference
Moving the WixUtilExtension.dll to c:\temp\bin (with all other wix binaries included) and referencing from there.
Moving the WixUtilExtension.dll to the same location as the Product.wxs and referencing from there.
Looking at the WixUtilExtension.dll with ILSpy to verify that it contains a reference to the http://schemas.microsoft.com/wix/UtilExtension namespace (it does in resources it contains an xsd with this namespace)
Any suggestions to get this working are welcome.
Ok,
I am here to answer my own question, hopefully to help someone else in the future.
The util:XmlFile tag needs to be inside a Component tag.
So the fixed fragment looks like this:
<Fragment>
<Property Id="HELLO" Value="Hello from install"/>
<Component Id="TestConfigComponent" Directory="INSTALLFOLDER">
<util:XmlFile
Id="UpdateHello"
Action="setValue"
File="$(var.TestWixError.TargetPath).config"
SelectionLanguage="XPath"
Permanent="yes"
ElementPath="/configuration/appSettings/add[\[]#key='Hello'[\] ]/#value"
Value="[HELLO]" />
</Component>
</Fragment>

WiX 3.11.1 -- error LGHT0103 : The system cannot find the file

WiX 3.11.1 on Windows 10 Pro Version 1703 64-bit. NOT using Visual Studio. Using simple text files as follows.
Here is a test case of the situation I am finding.
myapp.wxs is this:
<?xml version="1.0" encoding="UTF-8"?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi"
xmlns:netfx="http://schemas.microsoft.com/wix/NetFxExtension">
<Product Id="*"
Name="MyApp"
Language="1033"
Version="1.0.0.0"
Manufacturer="Me"
UpgradeCode="PUT-GUID-HERE">
<Package InstallerVersion="301"
Compressed="yes"
InstallScope="perMachine"
Manufacturer="Me"
Description="My App"
Keywords=".NET,Installer,MSI" />
<MediaTemplate EmbedCab="yes" />
<UIRef Id="WixUI_Minimal" />
<UIRef Id="WixUI_ErrorProgressText" />
<!-- ****************************************** -->
<WixVariable Id="WixUIDialogBmp"
Value="[CMP_Refresh_file]" />
<!-- ****************************************** -->
<Feature Id="MyFeature"
Title="MyApp Feature"
Description="Installs MyApp"
Level="1">
</Feature>
</Product>
<Fragment>
<Directory Id="TARGETDIR" Name="SourceDir">
<Directory Id="TestFolder" Name="TESTfolder" />
</Directory>
<Component Id="CMP_Refresh_file" Guid="*" Directory="TESTfolder">
<File Id="FILE_RefreshPNG" Source= "Refresh.png" KeyPath="yes" />
</Component>
</Fragment>
</Wix>
myapp.bat is:
"C:\Program Files (x86)\WiX Toolset v3.11\bin\candle.exe" myapp.wxs
"C:\Program Files (x86)\WiX Toolset v3.11\bin\light.exe" myapp.wixobj -ext WixUIExtension -ext WixUtilExtension
#pause
When I run the .bat file, it cannot find the CMP_Refresh_file (error LGHT0103 : The system cannot find the file). The folder TESTfolder is a direct sub-folder of the folder in which the .wxs file exists.
Substituting the full file path solves the issue. BUT that is not what I want as I will have a multitude of files and folders. (Also, if I put the file in the same folder as the .wxs file, of course, it finds it.)
I suspect it is purely a syntactic issue caused by my ignorance. In any case, I have tried endless variations of syntax for the Value of WixUIDialogBmp without joy (except the full name).
Help to resolve very much appreciated. Thanks!
Looking at your WiX code I can see that you are getting confused between the MSI destination and the source folder paths. The Directory tag is to create a folder on the machine where you run the MSI (where you want to deploy your application) - it has nothing to do with the source folders from where you package your files.
Replace your filepath with:
<File Id="FILE_RefreshPNG" Source= "\TESTfolder\Refresh.png" KeyPath="yes"/>
As you can see, the file -> source attribute path should be written with reference to your WXS file path.
If you are planning to deploy the refresh.png underneath the testfolder on the client machines then you got to move to closing </Directory> tag right after your <File> tag
Try <WixVariable Id="WixUIDialogBmp" Value="[#CMP_Refresh_file]" /> which references the installed path. See Formatted Strings for more info.
Came across this while trying to figure out a different issue with source file resolution. Isaiah4110's answer is misleading. The <Directory> structure can specify both the destination on the target machine and where to find the source files as long as the directory structure is the same. You just have to nest your <Component> elements within the corresponding directory elements and specify the Name attribute rather than Source.
In this case, the following should work:
<Directory Id="TARGETDIR" Name="SourceDir">
<Directory Id="TestFolder" Name="TESTfolder">
<Component Id="CMP_Refresh_file" Guid="*">
<File Id="FILE_RefreshPNG" Name="Refresh.png" KeyPath="yes" />
</Component>
</Directory>
</Directory>
This works because the Source of a <File> defaults to the source path of the <Component>'s parent <Directory> element (if there is one) plus the Name. See: File element reference and How to specify source files. Unfortunately this logic does not seem to work when placing the <Component> outside of the <Directory> structure as the example in the question does.

How to set the variable -var defined in heat.exe to the wxs file?

I am running the following command:
heat.exe dir bin\Release -sfrag -sreg -var var.sourcebin -dr myappfolder -cg myapp_comp_group
This generates a nice wxs file that looks a bit like this:
<?xml version="1.0" encoding="utf-8"?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
<Fragment>
<ComponentGroup Id="myapp_comp_group">
<ComponentRef Id="cmpE519314043C2FFE1104E067D33CBC652" />
<ComponentRef Id="cmp0431CFEC47E793CE59C185A8BDD9D865" />
</ComponentGroup>
</Fragment>
<Fragment>
<DirectoryRef Id="myappfolder">
<Directory Id="dir4ADCEBD4F8C9DC384017088D96B7A1C3" Name="somebinfolder">
<Component Id="cmpE519314043C2FFE1104E067D33CBC652" Guid="EB84C1A8-7BF5-4967-878D-8DAD9DFFA0A6">
<File Id="filD8C8D39058B0FF5C9608B1F99B0CD5BA" KeyPath="yes" Source="$(var.sourcebin)\app.config" />
</Component>
</Directory>
</DirectoryRef>
</Fragment>
</Wix>
I am using this by heat generated wxs file in my project, but I get an error, because the $(var.sourcebin) has not been set.
<?xml version="1.0" encoding="UTF-8"?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
<?define sourcebin="C:\svn\myapp\bin\Release"?>
<!-- leaving some stuff out of course -->
<Module>
<ComponentGroupRef Id="myapp_comp_group"/>
</Module>
</Wix>
error CNDL0150: Undefined preprocessor variable '$(var.sourcebin)'.
How do I define this variable so it is picked up by the heat generated file? I don't want to change the heat generated file manually, because it is re-generated every time.
Open project Properties, Choose Build tab and add preprocessor variable as needed.
sourcebin="C:\svn\myapp\bin\Release";
In the define section use:
<?define sourcebin = $(var.sourcebin)?>
Heat command you can leave as it is.
This will be the same when you will need to pass variables from msbuild (Wixproj file) to other files in your project(wxs,wxi...). Common use when using TFS.

Reference a heat generated wxs file from a merge module

I want to create a trivial merge module that contains all the files of a directory called "build" and installs them to the program files folder. I will use heat to generate a wxs file with all these files, and I want this to be separated from the wxs file I edit manually for the merge module. How do I reference the heat generated file from my other merge module wxs file?
I generate my heat wxs file like this:
heat dir build -cg heatComponent -gg -var var.buildFolder -dr ProgramFilesFolder -srd -out heatComponent.wxs
I know how to create an msi file of this:
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
<Product Name='product' Id='9f6edf70-539a-11e4-916c-0800200c9a66' UpgradeCode='bb651370-539a-11e4-916c-0800200c9a66'
Language='1033' Codepage='1252' Version='1.0.0' Manufacturer='Test'>
<Package Id='*' Description="A product" InstallerVersion='301' Languages='1033' Compressed='yes' SummaryCodepage='1252' Platform='x64'/>
<Media Id="1" Cabinet="product.cab" EmbedCab="yes" />
<Directory Id='TARGETDIR' Name='SourceDir'>
<Directory Id='ProgramFilesFolder'/>
</Directory>
<Feature Id="Files" Title="Main Feature" Level="1">
<ComponentGroupRef Id="heatComponent"/>
</Feature>
</Product>
</Wix>
But how do I do reference the ComponentGroup when I want to output a merge module? If I change the Product element to a Module element it complaints about the Feature element. If I remove that it works, but I do not get any files in my msm.
Based on the heat command you posted, try making your module definition (module1.wxs) look something like this:
<?xml version="1.0" encoding="utf-8"?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
<Module Id="Mod1" Language="0" Version="1.0.0">
<Package Id="YOUR-GUID" Manufacturer="Acme" />
<Directory Id="TARGETDIR" Name="SourceDir">
<Directory Id="ProgramFilesFolder" />
</Directory>
<ComponentGroupRef Id="heatComponent"/>
</Module>
</Wix>
Then you can call candle like so:
candle module1.wxs heatComponent.wxs -dbuildFolder="FOLDER-CONTAINING-FILES-HERE"
Followed by light like so:
light module.wixobj heatComponent.wixobj -o Module1.msm

patching using purely WIX

I am struggling with creating a patch purely using WIX and I was hoping if someone could guide me in the right direction.
I have a few hundred source files and I run heat against them to create a harvest file followed by creating a package using candle and light.
I need to change a few configuration files and I create a 2nd package with the changes.
Using Torch and pyro I create the .wixmst file and then when trying to create the msp file, pyro complains with the following error.
pyro.exe : error PYRO0252 : No valid transforms were provided to attach to the patch. Check to make sure the transforms you passed on the command line have a matching baseline authored in the patch. Also, make sure there are differences between your target and upgrade.
my question really is: what should patch.wxs contain?
Here is what my patch.wxs looks like:
<?xml version="1.0" encoding="UTF-8"?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
<Patch
AllowRemoval="yes"
Manufacturer="sample llc"
MoreInfoURL="sample.com"
DisplayName="Env Patch"
Description="Env Specfic Patch"
Classification="Update"
>
<Media Id="5000" Cabinet="RTM.cab">
<PatchBaseline Id="RTM" />
</Media>
<PatchFamilyRef Id="EnvPatchFamily" />
</Patch>
<Fragment>
<PatchFamily Id='EnvPatchFamily' Version='1.0.0.0' ProductCode="PUT-GUID-HERE" Supersede='yes' >
**********************************************
What component Ref should I put in here
heat creates a component group and I can't
put ComponentGroupRef in here
**********************************************
</PatchFamily>
</Fragment>
</Wix>
I am using Wix patching as described in this link:
http://wix.sourceforge.net/manual-wix3/wix_patching.htm
However, it doesn't consider source wix file created using heat.
Can someone tell me what am I doing wrong here?
Hitesh,
For me heat creates a component group like this:
<Fragment>
<ComponentGroup Id="MyFiles">
<ComponentRef Id="cmp2AA1A30564C621322ECB3CDD70B1C03C" />
<ComponentRef Id="cmp788C978F16E473D4FD85720B5B75C207" />
</ComponentGroup>
</Fragment>
heat command:
"%WIX%\bin\heat.exe" dir slndir\bin\Release -cg MyFiles -gg -scom -sreg -sfrag -srd -dr INSTALLDIR -out ..\Wix\MyFiles.wxs -var var.BinOutputPath -nologo -v -ke -t wixtransform.xsl
And in patch.wxs:
<Fragment>
<PatchFamily Id='ProductPatchFamily' Version='1.3.0.0' Supersede='yes'>
<ComponentRef Id="cmp2AA1A30564C621322ECB3CDD70B1C03C" />
<ComponentRef Id="cmp788C978F16E473D4FD85720B5B75C207" />
</PatchFamily>
</Fragment>
Take care: there is no ProductCode attribute in PatchFamily tag
I would also like to mention that PatchFamily elements are optional when building a patch, and are intended to allow fine grained control over exactly what will get patched. In most cases I find that I want to include all differences between 2 versions of an MSI when building a patch, in which case I omit the PatchFamily altogether. In your case, the resulting patch WXS would look like the following:
<?xml version="1.0" encoding="UTF-8"?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
<Patch
AllowRemoval="yes"
Manufacturer="sample llc"
MoreInfoURL="sample.com"
DisplayName="Env Patch"
Description="Env Specfic Patch"
Classification="Update"
>
<Media Id="5000" Cabinet="RTM.cab">
<PatchBaseline Id="RTM" />
</Media>
</Patch>
</Wix>
I hope this answer helps anyone with a similar question, that is not wanting to manually construct patch families, not wanting to manually includeComponentRef every time they need to build a patch.
I faced the same issue, the fix for this error is to add the GUID to the component and it should remain same for both the versions of msi.
<MajorUpgrade DowngradeErrorMessage="A newer version of [ProductName] is already installed." />
<MediaTemplate />
<Feature Id="ProductFeature" Title="WixPatch" Level="1">
<ComponentGroupRef Id="ProductComponents" />
</Feature>
</Product>
<Fragment>
<Directory Id="TARGETDIR" Name="SourceDir">
<Directory Id="ProgramFilesFolder">
<Directory Id="INSTALLFOLDER" Name="WixPatch" />
</Directory>
</Directory>
</Fragment>
<Fragment>
<ComponentGroup Id="ProductComponents" Directory="INSTALLFOLDER" >
<Component Id="File1" **Guid="3A64BE7A-BBEC-40AD-8319-45C602734146"**>
<File Source="D:\V2\File1.txt" Name="File1" KeyPath="yes" DiskId="1" Id="F1"/>
</Component>
</ComponentGroup>
</Fragment>