I am a student developer and I have built several installers for the company I am working with now. So I am fairly familiar with WIX.
We recently decided to have a Build server that auto builds our solution. It builds both debug, and release, as well as Obfuscated (and non obfuscated) projects.
And you really don't have to understand any of this. All you have to understand is that I have the same Wix project building different MSIs dynamically.
So the way we build them is we call MSBuild.exe with several parameters. Parameters the wix project depends on.
So let's say we go into command prompt and write
C:\>\windows\Microsoft.NET\Framework\v3.5\MSBuild.exe MyApp.Install\MyApp.Install.wixproj /p:Configuration=Release /p:SpecialPath=Obfuscated /t:Build
The idea is that wix sees the "SpecialPath" parameter being assigned "Obfuscated"; and in the installer paths its source to
..\myApp\bin\$(var.SpecialPath)\myApp.exe which translates to ..\myApp\bin\Obfuscated\myApp.exe when built.
TheQuestion
How do you create those custom build parameters and have them passed to my .wxs file. As of now with this setup, $(var.SpecialPath) is not defined and the build CrashSplosions.
For obvious legal reasons I had to cut 90% of the project.wxs file out and rename some stuff, but for all intents and purposes this is what I have.
<?xml version="1.0" encoding="UTF-8"?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
<Product Id="*" Name="myApp" Language="1033" Version="$(var.Version)" Manufacturer="myApp" UpgradeCode="$(var.UpgradeCode)">
<Package Id="*" InstallerVersion="200" Compressed="yes" />
<Media Id="1" Cabinet="media.cab" EmbedCab="yes" />
<Directory Id="TARGETDIR" Name="SourceDir" >
<Directory Id="ProgramFilesFolder">
<Directory Id="INSTALLLOCATION" Name="myApp">
<Component Id="myAppEXE" Guid="FD5EBC02-MY29-GUID-ACCA-61324C5F1B68">
<RegistryKey Root="HKLM" Key="Software\MyApp">
<RegistryValue Value="0" Type="string" KeyPath="yes"/>
</RegistryKey>
<File Id="MYAPPEXE" Name='myApp.exe' Source="..\myApp\bin\$(var.SpecialPath)\myApp.exe" />
</Component>
<Component Id="EngineDLL" Guid="*">
<File Id="ENGINEDLL" Name='Engine.dll' Source="..\myApp\bin\$(var.Configuration)\Engine.dll" />
</Component>
<Component Id="CommonDLL" Guid="*">
<File Id="COMMONDLL" Name='Common.dll' Source="..\myApp\bin\$(var.Configuration)\Common.dll" />
</Component>
</Directory>
</Directory>
</Directory>
<Feature Id="ProductFeature" Title="myApp" Description='All' Display='expand' Level="1" ConfigurableDirectory='INSTALLLOCATION'>
<ComponentRef Id="myAppEXE" />
<ComponentRef Id="EngineDLL" />
<ComponentRef Id="CommonDLL" />
</Feature>
</Product>
</Wix>
The reason it's not working for you is that you are setting msbuild properties on the command line, which are not getting passed through as wix variables. MSBuild properties and wix variables are two different concepts.
One way to fix this is to ignore the concept of msbuild properties and use environment variables to pass values directly to candle.exe. You can use environment variables in your wxs file like this:
$(env.SpecialPath)
You can then launch your setup build from a batch file which prepares the necessary environment variables like this:
#echo off
setlocal
set SpecialPath=foo
set Configuration=Release
set msbuild=C:\windows\Microsoft.NET\Framework\v3.5\MSBuild.exe
%msbuild% test.wixproj /t:Build || goto ERROR
exit /b 0
:ERROR
echo Failed to build setup!
exit /b 1
Alternatively, if you prefer to pass parameters via msbuild properties, you should first take a look at the msbuild candle task documentation. It shows you can set values in your wixproj file like this:
<DefineConstants>Variable1=value1;Variable2=value2</DefineConstants>
This still requires you to hardcode values in the wixproj file though. If you want to pass the values as msbuild properties on the command line, then you should probably do something like this:
<DefineConstants>Variable1=$(value1);Variable2=$(value2)</DefineConstants>
and then pass /p:value1=foo /p:value2=bar on the command line, or define these msbuild properties elsewhere.
As already answered, you need to pass the variables into WiX. We use Nant instead of MSBuild, but the concept remains the same.
Here's a Nant example passing in half a dozen variables to candle (it's not the cleanest example, but is lifted verbatim from a project I worked on)
<candle out="${dir.obj}\"
rebuild="true"
extensions="WixUIExtension;WixNetFxExtension">
<defines>
<define name="ProcessorArchitecture" value="${release.platform}" />
<define name="SourceDir" value="${dir.source}" />
<define name="version" value="${version}" />
<define name="releasetype" value="${release.type}" />
<define name="Language" value="${language}" />
<define name="product" value="${string.product}" />
<define name="productedition" value="${release.productedition}" />
</defines>
<sources>
<include name="*.wxs" />
<include name="..\Common\*.wxs" />
</sources>
</candle>
<!-- Define fallback culture for non-US -->
<property name="cultures" value="${language}" />
<property name="cultures" value="${language};en-US" unless="${language == 'en-US'}" />
<light
out="${dir.build}\setup_${release.platform}_${release.compressionlevel}.msi"
extensions="WixUIExtension;WixNetFxExtension;WixUtilExtension"
cultures="${cultures}"
rebuild="true"
suppressices="ICE03;ICE82"
suppresspdb="true" >
<arg line="-loc "setup-${language}.wxl"" />
<arg line="-sw1101" />
<arg line="-b ${dir.resources}" />
<arg line="-b ${dir.resources.common}" />
<arg line="-b ${dir.resources.common}\Microsoft" />
<arg line="-b ${dir.source}" />
<arg line="-dcl:${release.compressionlevel}" />
<arg line="-dWixUILicenseRtf=EULA_${language}.rtf" />
<sources>
<include name="${dir.obj}\*.wixobj" />
</sources>
</light>
I had a similar situation where the source path of the files was to be passed as a command line argument to the build script. This is what I did:
Edited the wixproj file and added the following content under the "PropertyGroup" node:
<Source Condition=" '$(Source)' == '' ">R:</Source>
where R: is the default directory/path from where to pick the source.
Now, the source can also be passed as a command line argument during build:
msbuild /t:Clean,Build "MyPath\MyWixProject.wixproj" /property:Source=MyConfigurablePath /p:Configuration=Release
Related
I've followed the official Major Upgrade guide and I seem to be missing something.
Here is my MCVE:
<?xml version="1.0" encoding="UTF-8"?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
<Product Id="*" Codepage="1252" Language="1033" Manufacturer="Bla Corporation"
Name="Bla" UpgradeCode="PUT-GUID-HERE" Version="31.00.0000">
<Package Comments="Contact: Refael Sheinker, refael.sheinker#bla.com." Description="Bla"
InstallerVersion="500"
Compressed="yes"
InstallScope="perMachine"
Keywords="Installer,MSI,Database" Languages="1033" Manufacturer="Bla Corporation" Platform="x64" />
<Media Id="1" Cabinet="my_application.cab" EmbedCab="yes" />
<MajorUpgrade AllowDowngrades="no"
AllowSameVersionUpgrades="no"
Disallow="no"
IgnoreRemoveFailure="no"
MigrateFeatures="yes"
Schedule="afterInstallInitialize"
DowngradeErrorMessage="A later version of [ProductName] is already installed" />
<Property Id="WIXUI_INSTALLDIR" Value="APPLICATIONROOTDIRECTORY" />
<UIRef Id="WixUI_InstallDir" />
<Directory Id="TARGETDIR" Name="SourceDir">
<Directory Id="ProgramFiles64Folder">
<Directory Id="PROGRAMFILESSUBDIR" Name="Bla">
<Directory Id="APPLICATIONROOTDIRECTORY" Name="BlaInternal" />
</Directory>
</Directory>
</Directory>
<DirectoryRef Id="APPLICATIONROOTDIRECTORY">
<Component Id="tenlira.ini" Guid="*">
<File Id="tenlira.ini" Source="..\ConfigurationFile\x64\tenlira.ini" KeyPath="yes" />
</Component>
</DirectoryRef>
<Feature Id="MainApplication" Title="TenLira" Level="1">
<ComponentRef Id="tenlira.ini" />
</Feature>
</Product>
</Wix>
All it does is simply installing a single file as an example. So far, so good. Now, all I do is add another Component and File and off course the corresponding ComponentRef in Feature. I specifically leave the Version as is: 31.00.0000. What I expected is that the new installer will not perform a Major Upgrade, but it does. Why? Also, there is now 2 entries in Add/Remove Programs.
Please help me find out what am I missing here. Thanks. Refael.
UPDATE:
Posting the question got me to reread the documentation again and I discovered that the AllowSameVersionUpgrades thingy in the MajorUpgrade element should be set to yes. This time there is only one entree in the Add/Remove Programs, but it still performs Major Upgrade. Why?
UPDATE: Here is a list to help debug failing major upgrades by identifying the most common problems: Common causes of failed major upgrades
Major Upgrade - "The Old, Manual Way"
I guess you are hitting an oddity that may not be handled entirely as expected by the WiX MajorUpgrade element by combining the auto-generated product GUID, the AllowSameVersionUpgrades set to yes and keeping the version number the same.
I can't see any obvious way to set the MinInclusive attribute in WiX's MajorUpgrade element - I could be mistaken, there might be a way I am unaware of. For what it is worth, I am not too keen on allowing "same version upgrades".
However, you could try to "use the old way" to author the Upgrade table using the "older elements" Upgrade and UpgradeVersion. The MajorUpgrade element is essentially a "convenience" feature to set up your major upgrades easily, and I believe it works for most users. Bob Arnson has a blog explaining the introduction of the MajorUpgrade element. This blog also shows a sample of how to do things "manually" with the "older elements" Upgrade and UpgradeVersion (do check it out).
I made a quick mock-up that might do what you want, it is just a "rough draft" - can't make any guarantees. I use preprocessor defines to set some variables that can be referenced in the WiX source file - as a C++ developer this is a piece of cake for you so I won't waste time explaining it - the source should make sense:
<?define MyProductVersion = "31.00.0000" ?>
<?define MyProductCode = "PUT-GUID-HERE" ?>
<?define MyUpgradeCode = "PUT-GUID-HERE" ?>
<!--Recommendation: set a path variable that you can redirect at will to a new release folder (new build output folder): -->
<!-- <?define MyBasePath = "C:\Projects\MyApp\Release\31.00.0000\" ?> -->
<!-- SAMPLE:
<Component Win64="yes" Feature="MainApplication">
<File Source="$(var.MyBasePath)\myapp.exe" />
</Component> -->
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
<Product Id="$(var.MyProductCode)" Codepage="1252" Language="1033" Manufacturer="Bla Corporation"
Name="Bla" UpgradeCode="$(var.MyUpgradeCode)" Version="$(var.MyProductVersion)">
<Package Comments="Contact: Refael Sheinker, refael.sheinker#bla.com." Description="Bla"
InstallerVersion="500"
Compressed="yes"
InstallScope="perMachine"
Keywords="Installer,MSI,Database" Languages="1033" Manufacturer="Bla Corporation" Platform="x64" />
<Media Id="1" Cabinet="my_application.cab" EmbedCab="yes" />
<!-- Major upgrade -->
<Upgrade Id="$(var.MyUpgradeCode)">
<!-- Downgrade Protection -->
<UpgradeVersion Minimum="$(var.MyProductVersion)" OnlyDetect="yes" IncludeMinimum="yes" Property="DOWNGRADE_DETECTED" />
<!-- Major Upgrade Configuration -->
<UpgradeVersion IncludeMinimum="no" Maximum="$(var.MyProductVersion)" IncludeMaximum="no" MigrateFeatures="yes" Property="UPGRADE_DETECTED" />
</Upgrade>
<!-- Major Upgrade: Schedule RemoveExistingProducts -->
<InstallExecuteSequence>
<!-- Potential scheduling (after): InstallValidate, InstallInitialize, InstallExecute, InstallExecuteAgain, InstallFinalize -->
<RemoveExistingProducts After="InstallInitialize" />
</InstallExecuteSequence>
<!--Launch Condition: Abort setup if higher version found-->
<Condition Message="!(loc.NewerVersionDetected)">
NOT DOWNGRADE_DETECTED
</Condition>
<Property Id="WIXUI_INSTALLDIR" Value="APPLICATIONROOTDIRECTORY" />
<UIRef Id="WixUI_InstallDir" />
<Directory Id="TARGETDIR" Name="SourceDir">
<Directory Id="ProgramFiles64Folder">
<Directory Id="PROGRAMFILESSUBDIR" Name="Bla">
<Directory Id="APPLICATIONROOTDIRECTORY" Name="BlaInternal" />
</Directory>
</Directory>
</Directory>
<DirectoryRef Id="APPLICATIONROOTDIRECTORY">
<Component Id="Test.ini" Guid="PUT-GUID-HERE" Win64="yes" Feature="MainApplication">
<CreateFolder Directory="APPLICATIONROOTDIRECTORY" />
<IniFile Id="SomeSetting" Action="addLine" Directory="APPLICATIONROOTDIRECTORY" Key="Setting1" Name="Test.ini" Section="MySection" Value="Some Setting" />
<IniFile Id="OtherSetting" Action="addLine" Directory="APPLICATIONROOTDIRECTORY" Key="Setting2" Name="Test.ini" Section="MySection" Value="Other Setting" />
</Component>
</DirectoryRef>
<Feature Id="MainApplication" Title="TenLira" Level="1">
<!--<ComponentRef Id="tenlira.ini" />-->
</Feature>
</Product>
</Wix>
Now the !(loc.NewerVersionDetected) has to be explained. This is a localized string (for delivering your setup in different languages). To use it, right click your WiX project in Visual Studio and go: Add New Item... => Localization File => Add. As the localization file is added, your output MSI will also now go into a en-us folder under your main output location (Debug or Release).
In the localization file, add:
<?xml version="1.0" encoding="utf-8"?>
<WixLocalization Culture="en-us" xmlns="http://schemas.microsoft.com/wix/2006/localization">
<String Id="NewerVersionDetected">A later version of [ProductName] is already installed.</String>
</WixLocalization>
And you should now be able to add new strings to this file and easily translate your whole setup using such language files.
Also add the WiX GUI extension. Right click "References". Add Reference... => Browse to WixUIExtension.dll => Double click this file, and press OK. Normal folder to find the file is: C:\Program Files (x86)\WiX Toolset v3.11\bin.
INI-Files
I just want to mention that INI files should ideally be installed via the IniFile table (entries are treated as atomic key-value pairs allowing advanced merging of keys and values for existing INI files), and not via the File table (the file is treated as a regular file either overwriting the whole existing file or leaving it in place - not enforcing any new values). The WiX element corresponding to the MSI IniFile table is naturally the IniFile element.
An ad-hoc sample:
<Component Id="Test.ini" Guid="PUT-GUID-HERE" Win64="yes" Feature="MainApplication">
<CreateFolder Directory="APPLICATIONROOTDIRECTORY" />
<IniFile Id="SomeSetting" Action="addLine" Directory="APPLICATIONROOTDIRECTORY" Key="Setting1" Name="Test.ini" Section="MySection" Value="Some Setting" />
<IniFile Id="OtherSetting" Action="addLine" Directory="APPLICATIONROOTDIRECTORY" Key="Setting2" Name="Test.ini" Section="MySection" Value="Other Setting" />
</Component>
Links:
Adding entries to MSI UpgradeTable to remove related products
It does a major upgrade because both MSIs have the same UpgradeCode and you have now specified AllowSameVersionUpgrades, so it does the upgrade where it didn't before.
Your build generates a new ProductCode every time, so each MSI is a new product, so you will get it installed twice if it doesn't do an upgrade and once if it does. You may have some assumption about the way upgrades work that you haven't spelled out.
I had the same problem where Version is same, but the Id is different creating multiple entries in Add/Remove programs.
My simple fix was to set AllowSameVersionUpgrades="yes".
<MajorUpgrade AllowSameVersionUpgrades="yes" DowngradeErrorMessage="A newer version of $(var.ServiceName) is already installed." />
I am using Wix to create my installer.
According to the official documentation, if I want to change the icon in Add/Remove Programs, I need to add this:
<Icon Id="icon.ico" SourceFile="MySourceFiles\icon.ico"/>
<Property Id="ARPPRODUCTICON" Value="icon.ico" />
But it does not works, the icon is not changed and I also get the following warning:
C:\Users\rsheink\home\repos\tenlira\10Lira\TestWiXProject\Product.wxs(137,0):
warning LGHT1076: ICE36: Icon Bloat. Icon icon.ico is not used in the
Class, Shortcut, or ProgID table and also not used for ARPPRODUCTICON
property.
What am I missing please?
Thanks. Refael.
Edit:
Following the excelent advice from #harper, here is the MCVE:
<?xml version="1.0" encoding="UTF-8"?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi"
xmlns:difx="http://schemas.microsoft.com/wix/DifxAppExtension">
<Product Id="*" Codepage="1252" Language="1033" Manufacturer="Intel Corporation"
Name="TenLira" UpgradeCode="PUT-GUID-HERE" Version="31.00.0000">
<Package Comments="Contact: Your local administrator" Description="TenLira" InstallerVersion="500"
Compressed="yes"
InstallScope="perMachine"
Keywords="Installer,MSI,Database" Languages="1033" Manufacturer="Intel Corporation" Platform="x64" />
<Media Id="1" Cabinet="my_application.cab" EmbedCab="yes" />
<MajorUpgrade AllowDowngrades="no"
AllowSameVersionUpgrades="no"
Disallow="no"
IgnoreRemoveFailure="no"
MigrateFeatures="yes"
Schedule="afterInstallInitialize"
DowngradeErrorMessage="A later version of [ProductName] is already installed" />
<Property Id="WIXUI_INSTALLDIR" Value="APPLICATIONROOTDIRECTORY" />
<UIRef Id="WixUI_InstallDir" />
<Directory Id="TARGETDIR" Name="SourceDir">
<Directory Id="ProgramFiles64Folder">
<Directory Id="PROGRAMFILESSUBDIR" Name="Intel Corporation">
<Directory Id="APPLICATIONROOTDIRECTORY" Name="TenLira">
<Directory Id="kmgl" Name="kmgl">
<Directory Id="kmgl_win10" Name="kmgl_win10" />
</Directory>
<Directory Id="tools" Name="tools" />
</Directory>
</Directory>
</Directory>
</Directory>
<DirectoryRef Id="tools">
<Component Id="devcon.exe" Guid="*">
<File Id="devcon.exe" Source="..\tools\devcon\amd64\devcon.exe" KeyPath="yes" />
</Component>
</DirectoryRef>
<Feature Id="MainApplication" Title="TenLira" Level="1">
<ComponentRef Id="devcon.exe" />
</Feature>
<!--It should set the icon in Add/Remove programs, but it does not works and I don't know why.-->
<Icon Id="icon.ico" SourceFile="..\TenLira icons\coins\coins.ico" />
<Property Id="ARPPRODUCTION" Value="icon.ico" />
</Product>
</Wix>
Request: Please comment if any of the below works for you - and also if you did something else (as well) to get things working.
Quick List First:
Is ARPPRODUCTICON spelled correctly?
Does the File.ico file have a hidden file extension? Example: icon.ico.bmp - 1.
Show file extensions in Windows Explorer
Open a cmd.exe in the folder and do a dir to check?
Icon file problems:
Is that a proper *.ico file? Try to save a normal *.bmp and rename the extension to *.ico. That should work for a rudimentary test icon.
Find a proper template *.ico file for testing (there should be plenty
in your Visual Studio installation folder).
UPDATE:
Please try to change this:
<Property Id="ARPPRODUCTION" Value="icon.ico" />
into this:
<Property Id="ARPPRODUCTICON" Value="icon.ico" />
I will leave the original answer below since the setup.exe issue might be relevant for others.
And one more thing: I was told that the dialog set <UIRef Id="WixUI_Mondo" /> is the better one in the available WiX templates. I have no hard facts apart from that recommendation though. I haven't used <UIRef Id="WixUI_InstallDir" /> - just if it can save you some time.
Old Answer:
This might just be a uppercase / lowercase issue. As in icon.ico instead of Icon.ico.
Correct:
<Icon Id="Icon.ico" SourceFile="MySourceFiles\Icon.ico"/>
<Property Id="ARPPRODUCTICON" Value="Icon.ico" />
Wrong:
<Icon Id="icon.ico" SourceFile="MySourceFiles\icon.ico"/>
<Property Id="ARPPRODUCTICON" Value="Icon.ico" />
During my testing I get the warning though, but the icon does work in Add/Remove Programs either way. Are you making a setup.exe bundle?
When you make a setup.exe bootstrapper bundle, you have to set the IconSourceFile attribute of the Bundle Element.
A link for safekeeping: How to customize icon for Wix custom bootstrapper.
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.
My first question is, should I work to get the compiler working with auto-generated guids?
I am trying to create an installer for a website with WiX. Please excuse my ignorance, this is my first WiX project. I am following this article:
http://blog.bartdemeyer.be/2013/10/create-an-installer-for-website-with-wix-part-1/
The process uses msbuild to call several WiX tools to ultimately create an MSI. The example uses "Generate guids now" (the "-gg" switch) when calling heat:
<Target Name="Harvest">
<!-- Harvest all content of published result -->
<Exec
Command='"$(WiX)bin\heat.exe" dir $(Publish) -dr INSTALLFOLDER -ke -srd -cg MgrWebComponents -var var.publishDir -gg -out $(WebSiteContentCode)'
ContinueOnError="false"
WorkingDirectory="." />
</Target>
I was reading elsewhere it is best practice to use auto-generated guids (the -ag switch) to ensure product updates install correctly. I notice the guids change every time heat is run.
<Fragment>
<ComponentGroup Id="MgrWebComponents">
<Component Id="cmp56294569B275493319100C26538BA16C" Directory="INSTALLFOLDER" Guid="{A43DA07B-C4CD-4FE0-AC09-EEA693AB2BA7}">
<File Id="fil93D55732EC03C2B809F21B9423BF5550" KeyPath="yes" Source="$(var.publishDir)\BrandImageService.ashx" />
</Component>
<Component Id="cmp6BD39B2D572EA73C29A81AE5D1C3F0C4" Directory="INSTALLFOLDER" Guid="{99B7B916-AEC0-4EE9-B17F-E7B325E93A4D}">
<File Id="filE861424851E26D456D43F5D1855B3E7B" KeyPath="yes" Source="$(var.publishDir)\Dashboard.aspx" />
</Component>
...
If I should use auto-generated guids I need to get the compiler working. I am getting errors for every file for trying to use auto-generated guids when compiling.
LGHT0231: The component 'cmp2BE6B5C092821452E1438D39A5110DDB' has a
key file with path 'TARGETDIR\inetpub\manager\tools\toolshome.aspx'.
Since this path is not rooted in one of the standard directories
(like ProgramFilesFolder), this component does not fit the criteria
for having an automatically generated guid. (This error may also
occur if a path contains a likely standard directory such as nesting a
directory with name "Common Files" under ProgramFilesFolder.)
My directory fragment is:
<Fragment>
<Directory Id="TARGETDIR" Name="SourceDir">
<Directory Id="INETPUB" Name="Inetpub">
<Directory Id="INSTALLFOLDER" Name="Manager" />
</Directory>
</Directory>
</Fragment>
The heat generated fragment looks like:
<Fragment>
<ComponentGroup Id="MgrWebComponents">
<Component Id="cmp56294569B275493319100C26538BA16C" Directory="INSTALLFOLDER" Guid="*">
<File Id="fil93D55732EC03C2B809F21B9423BF5550" KeyPath="yes" Source="$(var.publishDir)\BrandImageService.ashx" />
</Component>
<Component Id="cmp6BD39B2D572EA73C29A81AE5D1C3F0C4" Directory="INSTALLFOLDER" Guid="*">
<File Id="filE861424851E26D456D43F5D1855B3E7B" KeyPath="yes" Source="$(var.publishDir)\Dashboard.aspx" />
</Component>
...
The targets for msbuild:
<Target Name="Build">
<!-- Compile whole solution in release mode -->
<MSBuild
Projects="..\Manager.sln"
Targets="ReBuild"
Properties="Configuration=Release" />
</Target>
<Target Name="PublishWebsite">
<!-- Remove complete publish folder in order to
be sure that everything will be newly compiled -->
<Message Text="Removing publish directory: $(SetupF)"/>
<RemoveDir Directories="$(SetupF)" ContinueOnError="false" />
<Message Text="Start to publish website" Importance="high" />
<MSBuild
Projects="..\\Manager\UI\Manager.UI.csproj"
Targets="ResolveReferences;_CopyWebApplication"
Properties="OutDir=$(Publish)bin\;WebProjectOutputDir=$(Publish);Configuration=Release" />
</Target>
<Target Name="Harvest">
<!-- Harvest all content of published result -->
<Exec
Command='"$(WiX)bin\heat.exe" website $(Publish) -dr INSTALLFOLDER -ke -srd -cg MgrWebComponents -var var.publishDir -ag -out $(WebSiteContentCode)'
ContinueOnError="false"
WorkingDirectory="." />
</Target>
<Target Name="WIX">
<!-- At last create an installer -->
<Message Text="TEST: #(WixCode)"/>
<Exec
Command='"$(WiX)bin\candle.exe" -dpublishDir=$(Publish) -dMgrWebResourceDir=. #(WixCode, ' ')'
ContinueOnError="false"
WorkingDirectory="." />
<Exec
Command='"$(WiX)bin\light.exe" -spdb -out $(MsiOut) #(WixObject, ' ')'
ContinueOnError="false"
WorkingDirectory="." />
<!-- A message at the end -->
<Message Text="Install package has been created." />
</Target>
The build command is: msbuild /t:Build;PublishWebsite;Harvest;WIX setup.build
I understand the generated guid uses the seed of the directory. Should I change the location of the directory?
Thank you!!
Thank you to #CheGueVerra , he pointed me in the right direction. I just changed the directory location to be in ProgramFiles and it was able to compile.
<Fragment>
<Directory Id="TARGETDIR" Name="SourceDir">
<Directory Id="ProgramFilesFolder">
<Directory Id="INSTALLFOLDER" Name="Manager" />
</Directory>
</Directory>
</Fragment>
Later on I found a better way with the use of the "ComponentGuidGenerationSeed" attribute to keep the directory in the inetpub folder.
<Directory Id='TARGETDIR' Name='SourceDir'>
<Directory Id="IISMain" Name='inetpub'>
<Directory Id="WWWMain" Name='wwwroot'
ComponentGuidGenerationSeed='{Put-your-own-generated-guid-here}'>
<Directory Id='INSTALLFOLDER' Name='Manager'>
</Directory>
</Directory>
</Directory>
</Directory>
In my Product.wxs file I have the following element:
<WixVariable Id="MySourceDir" Overridable="yes" Value="C:\somePath\files\"/>
then in a heat generated wxs file I have something along the lines of:
<Fragment>
<ComponentGroup Id="FunctionalLibs">
<Component Id="cmp3A42AC690DA7590004EC5796B1C6BA95" Directory="dir5DCBEA4AA069AE7BD92B4A3EA9C5EC79" Guid="{8FD7F7BF-68C1-492C-8F29-8E3003A6F441}">
<File Id="fil007BA1D3A56EDEA1D669D51D8C61F518" KeyPath="yes" Source="!(wix.MySourceDir)\file1.dll" />
</Component>
</ComponentGroup>
</Fragment>
in my nant build file I have
<light exedir="${wix.dir}"
out="${output.dir}\PluginInstaller.msi"
cultures="en-us"
rebuild="true"
suppresspdb="true">
<sources basedir="${release.dir}\obj\\${configuration}">
<include name="*.wixobj" />
</sources>
</light>
How do I set the wix.MySourceDir value from the light task?
As described in the NAnt Task Reference for Light, you can add additional arguments to Light.exe using the <arg> tag. The command line reference for light.exe says we use -d to define WixVariables, so:
<light exedir="${wix.dir}"
out="${output.dir}\PluginInstaller.msi"
cultures="en-us"
rebuild="true"
suppresspdb="true">
<sources basedir="${release.dir}\obj\\${configuration}">
<include name="*.wixobj" />
</sources>
<arg line="-dMySourceDir=C:\somePath\files\" />
</light>
That should do the trick. However, perhaps the simpler, more supported, and more common way of defining a source directory like you're doing is using a preprocessor variable. The Candle Task supports them directly using the <defines> tag and the only change to your source code would be to change Source="!(wix.MySourceDir)\file1.dll" to Source="!(var.MySourceDir)\file1.dll".