I am using WIX with MSBuild. I am trying to copy a com library and a .ttf file to two different locations and I want to register the com library using WIX. When I run it using Visual Build Pro I don't see any errors or warnings and I can see the copy scripts being added to setup files. But the files are not copied to the specified directory after installing the setup.
Build.msbuild with <Target> as below:
<Target Name="Setup">
<!-- Setup the source directory structure as it should appear on the target machine -->
<ItemGroup>
<DeployFiles Include="$(Includes)" Exclude="$(Excludes)" />
<PostHarvestFiles Include="$(PostHarvestIncludes)" Exclude="$(PostHarvestExcludes)" />
</ItemGroup>
<MakeDir Directories="$(OutputDir)" />
<MakeDir Directories="$(FinalOutputDir)" />
<MakeDir Directories="$(FilesToInstallDir)" />
<!-- Harvest the newly created directory structure for the MSI -->
<Copy SourceFiles="#(DeployFiles)" DestinationFiles="#(DeployFiles->'$(FilesToInstallDir)\%(RecursiveDir)%(Filename)%(Extension)')" />
<Exec Command='$(BuildToolsDir)\Wix\heat.exe dir "$(FilesToInstallDir)" -dr INSTALLDIR -gg -cg FilesToInstall -sfrag -srd -sreg -out "$(MSBuildThisFileDirectory)Files.wxs" -var var.BaseDir' />
<Copy Condition="'%(Extension)' == '.ttf'" SourceFiles="#(PostHarvestFiles)" DestinationFiles="#(PostHarvestFiles->'$(FilesToInstallDir)\%(RecursiveDir)%(Filename)%(Extension)')" />
<!-- Harvest the old renderer DLL. This is a COM object and needs special handling -->
<Copy Condition="'%(Extension)' == '.dll'" SourceFiles="#(PostHarvestFiles)" DestinationFiles="#(PostHarvestFiles->'$(ComFilesToInstallDir)\%(RecursiveDir)%(Filename)%(Extension)')" />
<Exec Command='$(BuildToolsDir)\Wix\heat.exe file "$(ComFilesToInstallDir)\ComSrv.dll" -dr COMINSTALLDIR -ag -cg COMObjectsToInstall -out "$(MSBuildThisFileDirectory)COMDlls.wxs" -var var.ExternalsDir' />
</Target>
<Target Name="CompileWix" DependsOnTargets="Setup">
<!-- Create the Wix object files for linking in the next task -->
<ItemGroup>
<WixFiles Include="$(SourceDir)\Installer-Website\*.wxs" />
</ItemGroup>
<!-- Compile the Wix object files -->
<Exec Command="$(BuildToolsDir)\Wix\candle.exe -dBaseDir="$(FilesToInstallDir)" -dBuildToolsDir="$(BuildToolsDir)" -dExternalsDir="$(SourceDir)\ExternalAssembly" -dFinalVersion=$(FinalVersion) -ext WiXNetFxExtension -ext WixIisExtension -out $(OutputDir)\ #(WixFiles->'%(Filename)% (Extension)',' ')" />
</Target>
<Target Name="BuildMsi" DependsOnTargets="CompileWix">
<!-- Link the Wix object files into the final MSI -->
<ItemGroup>
<WixObjectFiles Include="$(OutputDir)\*.wixobj" />
</ItemGroup>
<!-- Link the Wix object files into the final MSI -->
<Exec Command="$(BuildToolsDir)\Wix\light.exe -cultures:en-us -loc "$(MSBuildThisFileDirectory)WebAppInstallDlg_en-us.wxl" -sice:ICE17 -sice:ICE38 -sice:ICE43 -sice:ICE57 -sice:ICE64 -ext WixUIExtension -ext WiXNetFxExtension -ext WixIisExtension -out $(OutputDir)\$(MsiName) #(WixObjectFiles->'%(FullPath)',' ')" />
<Copy SourceFiles="$(OutputDir)\$(MsiName)" DestinationFolder="$(FinalOutputDir)" />
</Target>
Product.wxs file with Directory as below:
<Directory Id="TARGETDIR" Name="SourceDir">
<Directory Id="INSTALLDIR" Name="$(var.BaseProductName)">
<Directory Id="FontsFolder">
<Component Id="cmp_FontsToInstall" Guid="{C286A08B-28CB-4A62-9BF8-833A6B141CB4}">
<File Id="fil82FBA6D3A96B47C48C72FA2F03739758" KeyPath="yes" TrueType="yes" Source="$(var.BaseDir)\OOCA.ttf" />
</Component>
</Directory>
<Directory Id="COMINSTALLDIR" >
<Component Id="COMObjectsToInstall" Guid="{5BAD46DE-D6AB-42D0-A13E-2407F8FBC97B}" >
<File Id="filE617B0B38D366E756290A5B22F2660C4" KeyPath="yes" TrueType="no" Source="$(var.BaseDir)\bin\ComSrv.dll" />
</Component>
</Directory>
.
.
.
.
</Directory>
</Directory>
I am new to this MSBuild and Wix. Can any one please point out what was is wrong in my script.
Thanks MikeR. I have included the files. But name of the property (PostHarvestIncludes) I have used is not spelled correctly. It is solved.
Related
I need to create an MSI for distribution, the old story but new situation. I don't use Visual Studio, only the Wix Toolset (3.11.2.4516). My files are under the msi folder:
MyFolder
|
---msi
| |
| ---Sample1.txt
| |
| ---Sample2.txt
|
---build.bat
|
---Product.wxs
Basically, I do harvest those files from the msi folder into an msi.wxs:
heat dir msi -cg MsiFilesGroup -dr MsiDir -gg -sfrag -srd -out msi.wxs
and I get a ComponentGroup called MsiFilesGroup. The main part (Product.wxs) defines an interactive WixUI to guide the user during the installation.
These Product.wxs defines a feature what references the above files:
<?xml version="1.0" encoding="utf-8" ?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
<Product Id="B858BC76-AD11-45c3-A300-D1C6B73DFF56" Name="Pruders" Language="1033" Version="0.0.0.0"
UpgradeCode="{FA34F953-F659-4633-B8D2-893BF7A63642}" Manufacturer="Microsoft Corporation">
<Package Description="Test WIXUI_INSTALLDIR" Comments="TestWIXUI_INSTALLDIR"
InstallerVersion="200" Compressed="yes" />
<Media Id="1" Cabinet="product.cab" EmbedCab="yes" />
<Feature Id="TestFileProductFeature" Title="Test File Product Feature" Level="1">
<ComponentRef Id="MsiFilesGroup" />
</Feature>
<Property Id="SQLCLRTYPES">
<RegistrySearch Id="SqlClrTypesSearch" Root="HKLM" Type="raw"
Key="SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall"
Name="KeyName1"/>
</Property>
<Property Id="WIXUI_INSTALLDIR" Value="TESTFILEPRODUCTDIR" />
<Property Id="WixAppFolder" Value="WixPerMachineFolder" />
<Property Id="buttonGroup" Value="1" />
<UIRef Id="WixUI_InstallDir" />
</Product>
</Wix>
If I use ComponentRef for referencing I get this error:
error LGHT0094 : Unresolved reference to symbol 'Component:MsiFilesGroup'
in section 'Product:{B858BC76-AD11-45C3-A300-D1C6B73DFF56}'
If I use ComponentGroup, it fails in this way:
Product.wxs(8) : error CNDL0005 : The Feature element contains an unexpected child element 'ComponentGroup'.
light.exe : error LGHT0103 : The system cannot find the file 'Product.wixobj' with type 'Source'.
Any hint would be a greate help.
The build.bat contains the calls of Wix commands, as it follows:
#echo off
del *.msi
del *.wix*
del msi.wxs
heat dir msi -cg MsiFilesGroup -dr MsiDir -gg -sfrag -srd -out msi.wxs
candle msi.wxs
candle Product.wxs
light -ext WixUIExtension msi.wixobj Product.wixobj -out Product.msi
It is the light.exe command that you are lacking, and there are a number of other things you need to adjust as well.
Here are two slightly modified and simplified batch and WiX sources. Notice the two *.wixobj files fed to light.exe and the -var var.sourcefolder added in there to set the source directory:
Suggested "Build.cmd":
#echo off
heat dir msi -cg MsiFilesGroup -dr INSTALLFOLDER -gg -sfrag -srd -suid -var var.sourcefolder -out msi.wxs
candle -dsourcefolder="msi" msi.wxs >> Build.log
candle Product.wxs >> Build.log
light -ext WixUIExtension Product.wixobj msi.wixobj -out Product.msi >> Build.log
rem pause
Suggested (simplified) "Product.wxs" - I find that only the Mondo dialog set is working "on its own" without any modification or fiddling:
<?xml version="1.0" encoding="utf-8" ?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
<Product Id="B858BC76-AD11-45c3-A300-D1C6B73DFF56" Name="Pruders" Language="1033" Version="0.0.0.0"
UpgradeCode="{FA34F953-F659-4633-B8D2-893BF7A63642}" Manufacturer="Microsoft Corporation">
<Package Description="Test WIXUI_INSTALLDIR" Comments="TestWIXUI_INSTALLDIR"
InstallerVersion="200" Compressed="yes" />
<Media Id="1" Cabinet="product.cab" EmbedCab="yes" />
<Feature Id="TestFileProductFeature" Title="Test File Product Feature" Level="1">
<ComponentGroupRef Id="MsiFilesGroup" />
</Feature>
<UIRef Id="WixUI_Mondo" />
</Product>
<Fragment>
<Directory Id="TARGETDIR" Name="SourceDir">
<Directory Id="ProgramFilesFolder">
<Directory Id="INSTALLFOLDER" Name="Test Folder" />
</Directory>
</Directory>
</Fragment>
</Wix>
<?xml version="1.0" encoding="UTF-8"?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
<Product Id="*" UpgradeCode="1" Version="1.0.0.0" Language="1033" Name="My Application Name" Manufacturer="My Manufacturer Name">
<Package InstallerVersion="300" Compressed="yes"/>
<Media Id="1" Cabinet="myapplication.cab" EmbedCab="yes" />
<!-- Step 1: Define the directory structure -->
<Directory Id="TARGETDIR" Name="SourceDir">
<Directory Id="ProgramFilesFolder">
<Directory Id="APPLICATIONROOTDIRECTORY" Name="My Application Name"/>
</Directory>
</Directory>
<!-- Step 2: Add files to your installer package -->
<!-- Copied from output from heat.exe -->
<Fragment>
<DirectoryRef Id="TARGETDIR">
<Directory Id="dirBF6284DAE096656A1A0B06AE3DCAA0C9" Name="MyAppName">
<Component Id="cmp26BABDEF350D4D06E3894ED92A9EA86E" Guid="8E1DA6FE-08EA-4D2E-8EBA-85131387A359">
<File Id="filEBD2DA63132D753815D44CEDC2ED5E88" KeyPath="yes" Source="SourceDir\benutzer.csv" />
</Component>
</Directory>
</DirectoryRef>
</Fragment>
<Fragment>
<ComponentGroup Id="MyComponentGroup">
<ComponentRef Id="cmp26BABDEF350D4D06E3894ED92A9EA86E" />
</ComponentGroup>
</Fragment>
<!-- Step 3: Tell WiX to install the files -->
<Feature Id="MainApplication" Title="Main Application" Level="1">
<ComponentGroupRef Id="MyComponentGroup" />
</Feature>
</Product>
</Wix>
Error:
error LGHT0094 : Unresolved reference to symbol ’Component:MyComponentGroup’ in section ’Product:*’.
I reduced the full code for this example, normally I would have many more files to be packaged. The component harvesting is done by heat.exe, I copied the components part into this wix file.
Although the error indicates what is the problem, I don't know what exactly to look for.
The code is run from a bat-file:
set WIX_BIN=c:\Program Files (x86)\WiX Toolset v3.11\bin\
echo Wix Toolset Bin Path: %WIX_BIN%
"%WIX_BIN%candle.exe" out.wxs -ext WixUtilExtension
if exist out.wixobj (
"%WIX_BIN%light.exe" -out out.msi out.wixobj -ext WixUIExtension -ext WixUtilExtension
)
pause
From my understanding, using DependsOnTargets is necessary to pass ItemGroup between targets. I am not sure if there are other ways to pass targets without DependsOnTargets.
I have tested that ItemGroup cannot pass from CallTarget or MSBuild task. A workaround solution is convert the ItemGroup to property (flatten it) and use Properties to pass over.
I define a ItemGroup of File. The File has Value metadata. I would like to execute target and remove one File item for each recursive loop. Here is my script:
<Target Name="MyGroup">
<ItemGroup>
<File Include="5">
<Value>5a</Value>
</File>
<File Include="4">
<Value>4a</Value>
</File>
<File Include="3">
<Value>3a</Value>
</File>
<File Include="2">
<Value>2a</Value>
</File>
<File Include="1">
<Value>1a</Value>
</File>
</ItemGroup>
</Target>
<Target Name="Recursive" DependsOnTargets="MyGroup" Condition="$(Value) > 0">
<ItemGroup>
<File Remove="$(Value)" />
</ItemGroup>
<PropertyGroup>
<Value>$([MSBuild]::Subtract($(Value), 1))</Value>
</PropertyGroup>
<Message Text="File: #(File->'%(Value)') Value=$(Value)" Importance="High" />
<MSBuild Projects="$(MSBuildProjectFile)" Targets="Recursive" Properties="Value=$(Value)"/>
</Target>
<Target Name="Build" DependsOnTargets="MyGroup">
<MSBuild Projects="$(MSBuildProjectFile)" Targets="Recursive" Properties="Value=5" />
</Target>
The output is:
File: 4a;3a;2a;1a Value=4
File: 5a;3a;2a;1a Value=3
File: 5a;4a;2a;1a Value=2
File: 5a;4a;3a;1a Value=1
File: 5a;4a;3a;2a Value=0
I expect the output to be:
File: 4a;3a;2a;1a Value=4
File: 3a;2a;1a Value=3
File: 2a;1a Value=2
File: 1a Value=1
File: Value=0
Is there a solution?
Not really, you are trying to circumvent idea of msbuild to build target only once (unless inputs\outputs changes).
And you can't pass itemgroups between MSBuild contexts (when you call MSBuild task - new context is created). Also in your script - ItemGroup is scoped to target - you need to define it globally so it'll be available to other targets.
What you can do is:
Define Global property Value with condition to use the one passed to script if exists.
Change ItemGroup from MyGroup target to global scope.
Define conditions on each element of itemgroup to be emitted depending on the value of Value property
e.g. your script will be something like this:
<?xml version="1.0" encoding="utf-8"?>
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<Value Condition="$(Value) == ''">5</Value>
</PropertyGroup>
<ItemGroup>
<File Include="5" Condition="$(Value) >5">
<Value>5a</Value>
</File>
<File Include="4" Condition="$(Value) >4">
<Value>4a</Value>
</File>
<File Include="3" Condition="$(Value) >3">
<Value>3a</Value>
</File>
<File Include="2" Condition="$(Value) >2">
<Value>2a</Value>
</File>
<File Include="1" Condition="$(Value) >1">
<Value>1a</Value>
</File>
</ItemGroup>
<Target Name="Recursive" Condition="$(Value) >0">
<PropertyGroup>
<Value>$([MSBuild]::Subtract($(Value), 1))</Value>
</PropertyGroup>
<Message Text="File: #(File->'%(Value)') Value=$(Value)" Importance="High" />
<MSBuild Projects="$(MSBuildProjectFile)" Targets="Recursive" Properties="Value=$(Value)"/>
</Target>
<Target Name="Build">
<MSBuild Projects="$(MSBuildProjectFile)" Targets="Recursive" Properties="Value=5" />
</Target>
</Project>
As Alexey Shcherbak points out, we can't pass ItemGroup from MSBuild task. I resolve my problem by introducing a new property Done to keep a list of item that has processed.
<Target Name="MyGroup">
<ItemGroup>
<File Include="5">
<Value>5a</Value>
</File>
<File Include="4">
<Value>4a</Value>
</File>
<File Include="3">
<Value>3a</Value>
</File>
<File Include="2">
<Value>2a</Value>
</File>
<File Include="1">
<Value>1a</Value>
</File>
</ItemGroup>
</Target>
<Target Name="Recursive" DependsOnTargets="MyGroup" Condition="$(Value) > 0" >
<ItemGroup>
<File Remove="$(Value)" />
<File Remove="$(Done)" />
</ItemGroup>
<Message Text="File: #(File->'%(Value)') Value=$(Value)" Importance="High" />
<PropertyGroup>
<Done>$(Done);$(Value)</Done>
<Value>$([MSBuild]::Subtract($(Value), 1))</Value>
</PropertyGroup>
<MSBuild Projects="$(MSBuildProjectFile)" Targets="Recursive" Properties="Value=$(Value);Done=$(Done)" />
</Target>
<Target Name="Build" DependsOnTargets="MyGroup">
<MSBuild Projects="$(MSBuildProjectFile)" Targets="Recursive" Properties="Value=5" />
</Target>
I'm using WIX 3.8 to create my setup file. This is my Product.wxs
<?xml version="1.0" encoding="UTF-8"?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
<Product Id="{D16E42B5-3C6F-4EE5-B2F4-727BF8B74A92}" Name="My setup" Language="1033" Version="1.0.0.0" Manufacturer="Me" UpgradeCode="9279b740-8419-45c4-9538-6a45f8e949c7">
<Package InstallerVersion="200" Compressed="yes" InstallScope="perMachine" />
<MajorUpgrade DowngradeErrorMessage="A newer version of [ProductName] is already installed." />
<Media Id="1" Cabinet="WCF.cab" EmbedCab="yes" />
<Feature Id="ProductFeature" Title="Wcf.Setup" Level="1">
<ComponentGroupRef Id="WCFComponents" />
</Feature>
<Property Id="WIXUI_INSTALLDIR" Value="INETPUB" />
</Product>
<Fragment>
<Directory Id="TARGETDIR" Name="SourceDir">
<Directory Id="INETPUB" Name="Inetpub">
<Directory Id="INSTALLFOLDER" Name="WCF">
</Directory>
</Directory>
</Directory>
</Fragment>
</Wix>
And here is the build file
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="3.5" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<WebSiteSource>..\WCF\</WebSiteSource>
<SetupF>..\Setup\</SetupF>
<PublishF>publish\</PublishF>
<Publish>$(SetupF)$(PublishF)</Publish>
<WebSiteContentCode>WebSiteContent.wxs</WebSiteContentCode>
<WebSiteContentObject>WebSiteContent.wixobj</WebSiteContentObject>
<MsiOut>bin\Release\WCF.msi</MsiOut>
<WixPath>C:\PROGRA~2\WIXTOO~1.8\bin\</WixPath>
</PropertyGroup>
<ItemGroup>
<WebSiteContent Include="$(WebSiteContentCode)" />
</ItemGroup>
<ItemGroup>
<WixCode Include="Product.wxs" />
<WixCode Include="$(WebSiteContentCode)" />
</ItemGroup>
<ItemGroup>
<WixObject Include="Product.wixobj" />
<WixObject Include="$(WebSiteContentObject)" />
</ItemGroup>
<Target Name="Build">
<MSBuild
Projects="..\TMS.sln"
Targets="ReBuild"
Properties="Configuration=Release" />
</Target>
<Target Name="PublishWebsite">
<Message Text="Removing publish directory: $(SetupF)"/>
<RemoveDir Directories="$(SetupF)" ContinueOnError="false" />
<Message Text="Start to publish website" Importance="high" />
<MSBuild
Projects="..\\WCF\WCF.csproj"
Targets="ResolveReferences;_CopyWebApplication"
Properties="OutDir=$(Publish)bin\;WebProjectOutputDir=
$(Publish);Configuration=Release" />
</Target>
<Target Name="Harvest">
<Exec
Command='$(WixPath)heat dir $(Publish) -dr INSTALLFOLDER -ke -srd -cg WCFComponents -var var.publishDir -gg -out $(WebSiteContentCode)'
ContinueOnError="false"
WorkingDirectory="." />
</Target>
<Target Name="WIX">
<Exec
Command='"$(WixPath)candle" -ext WixIISExtension -ext WixUtilExtension -ext WixSqlExtension -dpublishDir=$(Publish) -dMyWebResourceDir=. #(WixCode, ' ')'
ContinueOnError="false"
WorkingDirectory="." />
<Exec
Command='"$(WixPath)light" -ext WixIISExtension -ext WixUIExtension -ext WixUtilExtension -ext WixSqlExtension -out $(MsiOut) #(WixObject, ' ')'
ContinueOnError="false"
WorkingDirectory="." />
<Message Text="Install package has been created." />
</Target>
<Target Name="DeleteTmpFiles">
<RemoveDir Directories="$(Publish)" ContinueOnError="false" />
<RemoveDir Directories="$(SetupF)" ContinueOnError="false" />
<Delete Files="#(WixObject);#(WebSiteContent)" />
</Target>
</Project>
I always receive the error message: Product.wxs(10): error LGHT0094: Unresolved reference to symbol 'WixComponentGroup:WCFComponents' in section 'Product:{D16E42B5-3C6F-4EE5-B2F4-727BF8B74A92}'.
I copied exactly the source code from this topic http://blog.bartdemeyer.be/2013/10/create-an-installer-for-website-with-wix-part-1/ to my project but the source code from here runs property but mine doesn't work.
Could you please help me to solve this problem? Thanks a lot.
I solved this problem by removing Build parameter from command line.
It should be:
msbuild setup.build /t:Build;PublishWebSite;Harvest;WIX;DeleteTmpFiles
The reason is you can’t build your solution because MyProject.Setup can’t be built.
I have setup.exe. This is a Basic MSI Installation package. I use InstallShield to create it.
How can I get its FileVersion in MSBuild script?
I cannot use GetAssemblyIdentity task
<GetAssemblyIdentity AssemblyFiles="setup.exe">
<Output
TaskParameter="Assemblies"
ItemName="MyAssemblyIdentities"/>
</GetAssemblyIdentity>
because my setup.exe is not an assembly and doesn't contain an assembly manifest, so an error appears if invoke this task:
Could not load file or assembly 'setup.exe' or one of its
dependencies. The module was expected to contain an assembly manifest.
The FileVersionInfo class provides this functionality, and inline code allows using it from MSBuild directly:
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" >
<UsingTask TaskName="GetVersion" TaskFactory="CodeTaskFactory"
AssemblyFile="$(MSBuildToolsPath)\Microsoft.Build.Tasks.v4.0.dll" >
<ParameterGroup>
<TheFile Required="true" ParameterType="System.String"/>
<TheVersion ParameterType="System.String" Output="true" />
</ParameterGroup>
<Task>
<Code Type="Fragment" Language="cs">
<![CDATA[
TheVersion = System.Diagnostics.FileVersionInfo.GetVersionInfo( TheFile ).FileVersion;
]]>
</Code>
</Task>
</UsingTask>
<Target Name="DoGetVersion">
<GetVersion TheFile="$(MyAssemblyIdentities)">
<Output PropertyName="FetchedVersion" TaskParameter="TheVersion" />
</GetVersion>
<Message Text="Version = $(FetchedVersion)" />
</Target>
</Project>