How to extract NuGet contentFiles to a specific directory? - msbuild

What I've tried so far:
I've got the following .nuspec file, defining my package (simplified for better readability):
<package xmlns="http://schemas.microsoft.com/packaging/2011/08/nuspec.xsd">
<metadata>
.
.
.
<dependencies/>
<contentFiles>
<files include="any\any\config\*.*" buildAction="None" copyToOutput="true" flatten="false"/>
</contentFiles>
</metadata>
<files>
<file src="bin\Assembly.dll" target="lib\net461" />
<file src="bin\Assembly.pdb" target="lib\net461" />
<file src="Config\cf.xml" target="contentFiles\any\any\config"/>
<file src="Config\cf.txt" target="contentFiles\any\any\config"/>
</files>
</package>
As you can see, it contains a compiled Assembly along with it's debug symbols file as well as two content Files in a sub directory.
This results in the following compilation output, where the Assembly.dll is extracted to the output directory as well as the config sub directory (with the two cf.* files in it):
Question:
What I want to do is to move the sub directory config one step up in the directory tree, so it sits next to the output directory - basically maintaining the structure of the file input in the .nuspec file (assuming bin is the output directory of my .csproj):
How can I tell the NuGet package the exact location where I want the contentFiles to be extracted to?

You can achieve this by creating a MSBuild target that moves your config folder one level above the project build output.
Add a .targets file with the following content to your NuGet's build\net461 folder:
<?xml version="1.0" encoding="utf-8"?>
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<!-- Sets up items for target MoveConfigFiles, so that they can be used as Inputs and Outputs. -->
<Target Name="PrepareMoveConfigFiles" AfterTargets="Build">
<!-- ItemGroup wrapped in Target to delay evaluation of contained Items -->
<ItemGroup>
<!-- Contains source locations of files to be moved -->
<ConfigSourceFiles Include="$(OutputPath)\config\**\*.*" />
<!-- Contains target locations of files to be moved -->
<ConfigTargetFiles Include="#(ConfigSourceFiles->'%(FullPath)'->Replace('\config\', '\..\config\'))" />
</ItemGroup>
</Target>
<!-- Moves files from $(OutputPath)\config to $(OutputPath)\..\config,
then deletes $(OutputPath)\config. -->
<Target Name="MoveConfigFiles" AfterTargets="PrepareMoveConfigAndSqlFiles" Inputs="#(ConfigSourceFiles)" Outputs="#(ConfigTargetFiles)">
<Move SourceFiles="#(ConfigSourceFiles)" DestinationFiles="#(ConfigTargetFiles)" />
<RemoveDir Directories="$(OutputPath)\config" />
</Target>
</Project>
The target PrepareMoveConfigFiles is executed after the Build target (which guarantees the NuGet's contents exist in build output), and sets up items used as Inputs and Outputs of the next MoveConfigFiles target. (The items are set inside this target to ensure they are evaluated after the Build target has completed. If the item definitions would be placed below the Project level, they would be evaluated earlier and thus would potentially be empty because the files of the content folder have not yet been deployed.)
The ConfigSourceFiles item just contains the source files, and ConfigTargetFiles takes the paths of all ConfigSourceFiles and replaces \config\ with \..\config\, which leads to the desired target locations.
The MoveConfigFiles target then uses the Move and RemoveDir tasks to accomplish the movement of files and deletion of the original config folder.

It is a weird question...
You have several things to do a nuspec file;
The main are "the nuget packages".
Your nuspec line:
<file src="bin\Assembly.dll" target="lib\net461" />
<file src="bin\Assembly.pdb" target="lib\net461" />
I don't understand Assembly.pdb to distribute it, but is not important.
The goal of this lines are distribute yout dlls in your projects.
When you compile your solution (in your solution dir) it search for this dlls in same root application directory or else check if are register on system (gac mainly).
On the other hand other kind of lines are the "content" into nuget
<file src="Config\cf.xml" target="contentFiles\any\any\config"/>
<file src="Config\cf.txt" target="contentFiles\any\any\config"/>
This is additional content but maybe it may not will be used in the project.
If you want a route system you can use content, but you could have problems using the dlls.
So, I suppose that maybe you would this:
<file src="bin\Assembly.dll" target="contentFiles\any\any\bin" />
<file src="bin\Assembly.pdb" target="contentFiles\any\any\bin" />
<file src="Config\cf.xml" target="contentFiles\any\any\config"/>
<file src="Config\cf.txt" target="contentFiles\any\any\config"/>
And other nuspec example (I would not do this, but, it is possible to do it):
<files>
<file src="content\bin\youtBinayFile" target="content\bin\youtBinayFile" />
<file src="content\Config\YourConfigFile" target="content\Config\YourConfigFile" />
<file src="readme.txt" target="readme.txt" />
</files>
I hope I've helped

Related

Build target tools path

I am currently packaging a nuget package for my code generator project and I have gotten so far as to include an executable into the tools directory and a build target into the process.
Partial from the nuspec
<files>
<file src="cgbr.targets" target="build\cgbr.targets" />
<file src="cgbr.json" target="content\cgbr.json" />
<file src="..\bin\CGbR.Lib.dll" target="lib\CGbR.Lib.dll" />
<file src="..\bin\cgbr.exe" target="tools\cgbr.exe" />
</files>
Content of the cgbr.targets file
<?xml version="1.0" encoding="utf-8" ?>
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Target Name="BeforeBuild">
<Exec Command="cgbr.exe $(ProjectDir)"/>
</Target>
</Project>
Now when I install the package I see that it is included into the build process. Unfortunately the path to cgbr.exe is invalid and I am a little stuck. Of course I could use $(SolutionDir)packages\CGbR.0.3\tools\cgbr.exe but than I would have to modify it every time I change the version.
To clarify: I need the path to my packages tools path.
Edit: Found a related post
You probably want a relative path to the tool from the targets file. There are a number of predefined properties in msbuild. Perhaps the most useful for these scenarios is MSBuildThisFileDirectory which returns the full path to the directory of the current proj file. An example:
<Exec Command=""$(MSBuildThisFileDirectory)..\tools\cgbr.exe" "$(ProjectDir)""/>

Include all Files in Bin folder in Wix installer

I'm new in Wix, I succefully create an MSI installer for my project, but my Bin folder have a lot of DLL's files with EXE main file, I want to include all these files with the installer
I found THIS solution, that seems right but unfortunately I can not accomplish this solution in my Wix file, Here's my Wix file:
<Product Id="*" Name="Setup"
Language="1033" Version="1.0.1.0"
Manufacturer="ORDER MS"
UpgradeCode="a4f0a0d0-ae64-4f62-9bb3-efa7e75072e0">
<Package InstallerVersion="200"
Compressed="yes"
InstallScope="perMachine" />
<MajorUpgrade Schedule="afterInstallInitialize"
DowngradeErrorMessage="A newer version of [ProductName] is already installed." />
<MediaTemplate />
<Feature Id="ProductFeature" Title="Setup" Level="1">
<ComponentGroupRef Id="ProductComponents" />
<ComponentRef Id="ApplicationShortcutDesktop" />
<ComponentRef Id="ApplicationShortcut" />
</Feature>
<Icon Id="Icon.exe" SourceFile="$(sys.CURRENTDIR)\icon.ico"/>
<Property Id="ARPPRODUCTICON" Value="icon.exe" />
<ComponentGroup Id="ProductComponents" Directory="INSTALLFOLDER">
<Component Id="ProductComponent">
<File Source="$(var.Order.TargetPath)" />
</Component>
<Component Guid="A7C42303-1D77-4C70-8D5C-0FD0F9158EB4" Id="CopyComponent">
<CopyFile Id="SomeId"
SourceProperty="SOURCEDIRECTORY"
DestinationDirectory="CopyTestDir" SourceName="*" />
</Component>
</ComponentGroup>
I get this Error:
Error 1 ICE18: KeyPath for Component: 'CopyComponent' is Directory: 'INSTALLFOLDER'. The Directory/Component pair must be listed in the CreateFolders table.
This solution works with WIX 3.11.
To harvest an entire directory, you can use Heat from the WIX toolset. With Heat we can automatically include all files from a given source directory on every build. To do that we first need to edit the Setup.wixproj:
Define the Harvestpath for Heat:
<PropertyGroup>
<DefineConstants>HarvestPath=...\Deploy</DefineConstants>
</PropertyGroup>
Heat will create a .wxs file. So we need to add this file to the compile ItemGroup:
<ItemGroup>
<Compile Include="Product.wxs" /> <!-- This will be your default one -->
<Compile Include="HeatGeneratedFileList.wxs" /> <!-- This is the Heat created one -->
</ItemGroup>
Then execute Heat in the BeforeBuild build target:
<Target Name="BeforeBuild">
<HeatDirectory Directory="..\Deploy"
PreprocessorVariable="var.HarvestPath"
OutputFile="HeatGeneratedFileList.wxs"
ComponentGroupName="HeatGenerated"
DirectoryRefId="INSTALLFOLDER"
AutogenerateGuids="true"
ToolPath="$(WixToolPath)"
SuppressFragments="true"
SuppressRegistry="true"
SuppressRootDirectory="true" />
</Target>
This will generate the HeatGeneratedFileList.wxs every time the WIX installer is built. The directory ..\Deploy has to be set to the directory of the files to include.
The only thing we have to do to include these files in our installer is to edit the main .wxs file (like Product.wxs in this example). Heat will create a ComponentGroup with the given name from above. This component needs to be referenced in the Feature section of the Product.wxs:
<Feature Id="ProductFeature" Title="DiBA Tool" Level="1">
<...>
<ComponentGroupRef Id="HeatGenerated" />
</Feature>
I think you've gotten into a bit of a muddle, if you don't mind me saying so.
CopyFile will copy a file will copy a file from one place on a target machine (the machine where the install is being installed, not your development computer) to another folder on the same machine. I don't think this is what you want.
As Brian suggested you can use Heat to scan a folder and generate some code for you. You can use that in one of two ways:
As a development aid
Run the tool with this kind of command:
heat dir ".\My Files" -gg -sfrag -template:fragment -out directory.wxs
Then, take directory.wxs and use it as source code.
In the build pipeline
You can use the Heat tool in the build pipeline, so that compiling the install will generate the code.
Contrary to Brian's suggestion, if you are using MSBuild I would suggest the HarvestDirectory target. Here's what I have where I am doing something similar:
<HarvestDirectory Include="$(MyHarvestDirectory)">
<InProject>false</InProject>
<PreprocessorVariable>var.MyHarvestDirectory</PreprocessorVariable>
<ComponentGroupName>MyComponentGroup</ComponentGroupName>
<DirectoryRefID>MY_DIRECTORY_ID</DirectoryRefID>
</HarvestDirectory>
This will feed an item into the HarvestDirectory target and make sure it's all handled in the correct way. This code just goes into an ItemGroup in your .wixproj. (If you're not sure how to tweak your project file, check out this video)
Of course, this assumes you are using MSBuild (or Visual Studio, because that uses MSBuild).
Caveat
Having said all this, if the main issue is simply that there are lots of files, I would simply say knuckle down and just define the list. Use the Heat tool as a scaffold if you like, but there's no substitute for just learning the language and working with it. Trying to do things with auto generated code can introduce subtle issues, and it's always simpler to work with a static list.
I do something similar to what you require here during my installation. I need to copy the contents of a folder with 1000+ files in it (the help files).
What I did to solve this is the following:
In the Installer.wixproj I defined the following:
<Target Name="BeforeBuild" >
<Exec Command=""$(WixToolPath)Heat.exe" dir "$(MSBuildThisFileDirectory)\$(Configuration)\bin" -ag -cg BinDir -dr BIN -template fragment -sreg -sfrag -srd -var var.BinDir -o "$(MSBuildThisFileDirectory)\Components\Bin.wxs"" Condition="!Exists('$(MSBuildThisFileDirectory)\Components\Bin.wxs')" />
</Target>
And this will run heat on the $(Configuration)\bin\ dir and generate a wxs file including ALL the files in the bin dir.
This way if you add or delete any binaries in your bin dir it will automatically get picked up when you rebuild your installer (if the Bin.wxs file doesn't exist).
Now you need to make sure you define the variable "BinDir" for wix which points to the bin dir on the build machine. You also need to add the Bin.wxs file to your wixproj as a link (when adding existing file there's a tiny arrow drop down on "Add". Click that and select "Add as link".)
I think there's an actual heat target somewhere in wix but I haven't looked through that enough to know how to use it yet.
As an alternative to the other answers:
There is a Visual Studio extension called Wax (GitHub, Visual Studio Marketplace):
It provides an alternative way to handle all the required files with GUI.
It may be not as sophisticated as command-line tools like heat, but it is much simpler and can be a nice and friendly tool in the beginning, when you just start learning WiX - and want a quickstart.

Installer conditionally picking up files

I'm building a Wix installer and I need two separate versions of said installer. One that picks up the latest development build of the project and one that picks up the latest release build. Currently my fragment looks like this:
<Property Id="Program.ReleaseBuild" Value="0" />
<?define ReleaseBuild = [Program.ReleaseBuild]?>
<Fragment>
<ComponentGroup Id="ProductComponents" Directory="InstallFolder">
<Component Id="TheExe" Guid="GUID_GOES_HERE">
<?if $(var.ReleaseBuild) = 1?>
<File Id="ProjectExe" Source="(Rel Project Path)/program.exe" />
<?else?>
<File Id="ProjectExe" Source="(Dev Project Path)/program.exe" />
<?endif?>
</Component>
</ComponentGroup>
</Fragment>
And I have a transform on the msi that transforms the file after build. But the problem is that the file is picked up on compile time not install time, so both version of the installer end up having the same file contained in them. Any idea how I can conditionally grab a dev file or a rel file in the same wix project?
If you want to create installation packages based on build quality (debug versus release), you can use two product configuration and select the source based on it. This way, you can run msbuild twice, one for each configuration. I don't understand the purpose of the transform you mentioned.
So here are steps you could take to accomplish this:
Create an empty solution.
Add your wixproj to it.
Add your csproj to it.
Add a reference of the csproj to the wixproj.
Modify your File[Source] to use the project reference, this way:
<File Source="$(var.MyProject.TargetPath)" Id="ProjectExe" />
The $(var.MyProject.TargetPath) will automatically get the exe from the correct path.
Create a batch file to run the msbuild twice, one for each configuration, with the following commands:
C:\> msbuild mySolution.sln /p:Configuration=Debug
C:\> msbuild mySolution.sln /p:Configuration=Release
The result will be two installation packages, one for each configuration.

Using Wix how can I deploy one of several web.config files while installing an ASP.net web application

I'm using Wix 3.6 beta from the command line, not as VS projects. I have a web application that is harvested with heat as a directory. This works. I'm using web.config transforms to manage each of the target environment web.config files. These are output with msbuild, this works and keeps things visible in Visual Studio and source control.
I've hit a problem deploying one of the several web.config files which I am manually including in product.wxs as components with conditions. I was expecting to include all components as deployable features and let the conditions select just one as active. For example:
<DirectoryRef Id="wwwroot">
<Component Id="setup_a" Guid="some_guid" >
<File Source="$(var.ConfigSourceDir)\setup_a\web.config" />
<Condition>ENVIRON = setup_a</Condition>
</Component>
<Component Id="setup_b" Guid="some_guid" >
<File Source="$(var.ConfigSourceDir)\setup_b\web.config" />
<Condition>ENVIRON = setup_b</Condition>
</Component>
This didn't create any file renaming, moving or deleting issues, but has the very fundamental problem that multiple web.config files are mapped to the same destination and this gives me a light error of "Product.wxs(xxx) : error LGHT0091 : Duplicate symbol 'File:web.config' found. This typically means that an Id is duplicated. Check to make sure all your identifiers of a given type (File, Component, Feature) are unique."
An alternative approach was to use different named .config files and rename/move one to be the web.config, so something like:
<DirectoryRef Id="wwwroot">
<Component Id="setup_a" Guid="some_guid" >
<File Id="setup_a.config" Source="$(var.ConfigSourceDir)\setup_a.config" />
<CopyFile Id="moveit" SourceDirectory="wwwroot" SourceName="setup_a.config" DestinationDirectory="wwwroot" DestinationName="web.config" />
</Component>
This doesn't throw an error, bot the CopyFile command does nothing at all. I just get setup_a.config in the wwwroot folder.
If I nest the CopyFile inside the File, the copy action then works:
<DirectoryRef Id="wwwroot">
<Component Id="setup_a" Guid="some_guid" >
<File Id="setup_a.config" Source="$(var.ConfigSourceDir)\setup_a.config" >
<CopyFile Id="moveit" DestinationName="web.config"/>
</File>
</Component>
...but nested CopyFile means I can't add (it's disallowed) the Delete="yes" attribute to create a 'move' action. Instead I'm left with both setup_a.config and web.config in the wwwroot folder. Alternatively, if I add a seperate removefile within the same component element it also does nothing:
<RemoveFile Id="removefile" On="install" Directory="wwwroot" Name="setup_a.config"/>
</Component>
So, I'm hoping for a working example of how handle multiple web.config files in a conditional deployment, that doesn't leave files behind. the destination filename of web.config is fixed by the framework and can't be changed. The different configs are also pre-generated outside of wix using config transforms, this also can't be changed but the generated filenames could be anything.
cheers!
You complicate it too much. This should work:
<Component Id="setup_a" Guid="some_guid" >
<File Name="web.config" Id="config_a" Source="$(var.ConfigSourceDir)\setup_a\web.config" />
<Condition>ENVIRON = setup_a</Condition>
</Component>
<Component Id="setup_b" Guid="some_guid" >
<File Name="web.config" Id="config_b" Source="$(var.ConfigSourceDir)\setup_b\web.config" />
<Condition>ENVIRON = setup_b</Condition>
</Component>
Pay attention to a couple of things here:
the File/#Name is the same - that's the target file name you'd like to have (web.config)
the File/#Id is different for each File in order to avoid the light error you mentioned first
the File/#Source can be anything - it just describes what file to take as a source
In this sample light will still complain with warning LGHT1076, but that's just a warning - it pays your attention that conditions MUST be mutually exclusive to avoid problems.
I usually take a different approach. Rather then placing multiple mutually exclusive files into an installer that are tightly coupled to specific instances I put a generic file in the installer and use XML changes to transform the XML with the variation point data such as connection string and what not.
This allows me to make installers that can be deployed anywhere silently just by passing a few properties and the command line.

WIX: Howto set the name of the msi output file dynamically

I want to include some dynamic part in the filename of the msi file my wix projects produce. This dynamic part should be controlled by variables which are part of my wix project and are declared like this:
<?define ProductVersion="7.1.0.1" ?>
Does anybody know about a way of sending that value of that wix variable to the linker to use it as a part of the output filename?
By the way: I'm using Wix3
You could update the OutputName of your .wixproj and use an MSBuild variable to pass through the version number or any other variable you like.
My build script looks like this:
set PRODUCTVERSION=7.1.0.1
MSBuild.exe /p:Configuration=Debug /p:ProductVersion=%PRODUCTVERSION% Installer.wixproj
And my WiX project looks like this:
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">x86</Platform>
<ProductVersion>1.0.0.0</ProductVersion>
<ProjectGuid>{b7415c44-8d59-4ac2-b698-03e399a305e3}</ProjectGuid>
<SchemaVersion>2.0</SchemaVersion>
<OutputName>Installer.$(ProductVersion)</OutputName>
...
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x86' ">
<OutputPath>bin\$(Configuration)\</OutputPath>
<IntermediateOutputPath>obj\$(Configuration)\</IntermediateOutputPath>
<DefineConstants>Debug</DefineConstants>
<WixVariables>ProductVersion=$(ProductVersion)</WixVariables>
</PropertyGroup>
...
</Project>
The output would be:
Installer.7.1.0.1.msi
The msi file name is not determined by your wix files, but by the light.exe -out switch. You can use the same value for -out and inside your wix files if you do the following in your build script, assuming it is a batch script:
set an environment variable with set
productversion=1.2.3
Pass -out foo%productversion%.msi to the
light.exe linker
use the same environment variable in
your wix files as
$(env.productversion)
Open *.wixproj (example: Setup.wixproj)
Go to the end of the file.
$(Configuration) = Debug| Release …
Set path of your application on AssemblyFiles.
<Target Name="BeforeBuild">
<GetAssemblyIdentity AssemblyFiles="..\App\bin\$(Configuration)\App.exe">
<Output TaskParameter="Assemblies" ItemName="AsmInfo" />
</GetAssemblyIdentity>
<CreateProperty Value="$(SolutionName)_%(AsmInfo.Version)_$(Configuration)">
<Output TaskParameter="Value" PropertyName="TargetName" />
</CreateProperty>
</Target>
Output = App_1.0.0.0_Debug.msi
I found a couple of great reference posts to do just this operation:
http://blog.tentaclesoftware.com/archive/2009/05/03/38.aspx
and a follow-on with a better method of creating the output file using a pre-build event:
http://blog.tentaclesoftware.com/archive/2010/08/05/99.aspx
I know the links are old, but the method is sound.
Here are the basic steps:
Put the version you wish to use into a file you can access from your project. I use the main executable of my installation because I also bind to that version in my wxs. In my case, since I am building with C# and use SVN, I have a template version of my assembly.cs, assembly.cs.txt, that I run subwcrev on as a pre-build event to create the assembly.cs that gets compiled into my executable (I actually do it in a separate project in my solution). Subwcrev inserts some date and revision information that I use to create a version in the form "major.minor.version.0" where I use "year.month.revision.0" for my version.
Now, I usually just set AssemblyFileVersion with this method, but to be able to use my version number in the wixproj build event referenced in the post above, I also need to set AssemblyVersion since that is what can be accessed with GetAssemblyIdentity. This method would be questionable if I were really using an assembly someone else links to, but for me it is OK since it is in my final application executable.
Follow the steps outlined in the second post (the first post discusses using the binding method for version in wxs and how to unload and edit the wixproj - valuable context for the second post).
Works like a charm!
Update some years later - it looks like the links I referenced are dead. Here is a snapshot of what I changed to make it work.
In my main product wxs file, I changed (some names have been changed or omitted to protect the innocent and the guilty):
<ComponentGroup Id="ProductComponents" Directory="INSTALLFOLDER">
<!-- TODO: Remove the comments around this Component element and the ComponentRef below in order to add resources to this installer. -->
<Component Id="ProductComponent" Guid="DF1AB3A6-17D0-4176-B3AC-C073AC47AA80">
<RemoveFile Id="PurgeAppFolder" Name="*.*" On="uninstall" />
<File Source="$(var.MyApp.TargetPath)" KeyPath="yes"/>
<File Source="$(var.MyApp.ProjectDir)\bin\Release\MyData.dll"/>
<File Source="$(var.MyApp.ProjectDir)\bin\$(var.MyApp.Configuration)\ICSharpCode.SharpZipLib.dll"/>
</Component>
</ComponentGroup>
to
<ComponentGroup Id="ProductComponents" Directory="INSTALLFOLDER">
<!-- TODO: Remove the comments around this Component element and the ComponentRef below in order to add resources to this installer. -->
<Component Id="ProductComponent" Guid="DF1AB3A6-17D0-4176-B3AC-C073AC47AA80">
<RemoveFile Id="PurgeAppFolder" Name="*.*" On="uninstall" />
<File Id="MAINEXECUTABLE" Source="$(var.MyApp.TargetPath)" KeyPath="yes">
<Shortcut Directory="ApplicationProgramsFolder" Id="MYAPPEXEAPF" Name="My App Name" Icon="MyAppIcon.exe" IconIndex="0" Advertise="yes" />
<Shortcut Directory="ApplicationDesktopFolder" Id="MYAPPEXEADF" Name="My App Name" Icon="MyAppIcon.exe" IconIndex="0" Advertise="yes" />
</File>
<File Source="$(var.MyApp.ProjectDir)\bin\Release\MyData.dll"/>
<File Source="$(var.MyApp.ProjectDir)\bin\$(var.MyApp.Configuration)\ICSharpCode.SharpZipLib.dll"/>
</Component>
</ComponentGroup>
and up at the top I added:
<Product Id="C86505BF-303F-4D6B-8F5F-43A57635F85D" Name="My Application Name" Language="1033" Version="!(bind.FileVersion.MAINEXECUTABLE)" Manufacturer="My Software Shop" UpgradeCode="D1C628E5-5478-4DA5-A31A-F9191D5B1544">
Note that the Version is bound to the file version of MAINEXECUTABLE, which is defined in the main product component.
I hope this helps!
If you have several configurations then inside .wixprj file you can do the following
<OutputName Condition="'$(Configuration)' == 'User'">User.Setup</OutputName>
<OutputName Condition="'$(Configuration)' == 'Designer'">Designerr.Setup</OutputName>
Since it's just a file name, why not have a post-build action that renames the file in your build script (assuming MSBuild)?
Do the variables have to be defined in WiX? I'm building my setup binaries from MSBuild, and I've simply set the output file name to MyProject_$(Platform) -- I expect that any MSBuild variable substitution will work equally well.
Product Id="GUID" Name="whatevername $(var.ProductVersion)"