I'm using Wix toolset v 3.11 in VS2019 to create a setup for our application. In order to ease maintenance, I need to copy the installer files to a folder with the version in its path.
Basically what I thought was to use a post build event where I would copy the files to a \$(BootstrapPackageVersion)\$(Configuration)\ directory, but I am not able to find such variable.
I tried to extract the version from the .exe package (since it gets its version from the MSI package that itself get its version from the original application, as intended) with the following code in the .wixproj file:
</PropertyGroup>
<Target Name="AfterBuild">
<GetAssemblyIdentity AssemblyFiles="$(TargetPath)">
<Output TaskParameter="Assemblies" ItemName="AssemblyVersions" />
</GetAssemblyIdentity>
<CreateProperty Value="$(TargetDir)/%(AssemblyVersions.Version)/">
<Output TaskParameter="Value" PropertyName="CustomTargetName" />
</CreateProperty>
<Copy SourceFiles="$(TargetDir)/*" DestinationFolder="$(CustomTargetName)"/>
</Target>
But it fails with the following error:
Cannot get assembly name for "[Path]\Setup.exe". Could not load file
or assembly 'Setup.exe' or one of its dependencies. The module was
expected to contain an assembly manifest.
I saw that there is a property, $(WixBundleVersion), but it doesn't seems to be available to use in build events.
Basically what I want to achieve is a fairly simple thing: take the output from the bootstrapper project and copy everything to another path that include the package version. It is possible?
The way I do this in my wix project is to output setup.exe into it's default folder and then run an AfterBuild and copy it to the final artifacts directory
in wixproj:
<Target>
...
<GetAssemblyIdentity AssemblyFiles="..\MyApp.App\bin\$(Configuration)\net5.0\FrameworkDep\win-$(Platform)\Publish\MyApp.App.dll">
<Output TaskParameter="Assemblies" ItemName="AssemblyVersion" />
</GetAssemblyIdentity>
<PropertyGroup>
<DefineConstants>BuildVersion=%(AssemblyVersion.Version)</DefineConstants>
</PropertyGroup>
...
</Target>
<Target Name="AfterBuild">
<Copy SourceFiles=".\bin\$(Configuration)\en-us\$(OutputName).msi" DestinationFiles=".\bin\$(Configuration)\$(OutputName)_%(AssemblyVersion.Version).msi" />
</Target>
This assigns
BuildVersion which you can then use in your wxs files
and
AssemblyVersion which you can use in the wixproj with %(AssemblyVersion.Version)
the AfterBuild section is copying the msi to
MyApp_1.2.3.msi
in my wxs file I can use:
<Product Id="*" Name="My App" Language="1033"
Version="$(var.BuildVersion)>
This is then using the build version from above so I just version control MyApp.App project.
Related
I have a program that i just built an installer for with wix and im now trying to get the assemblyversion of my program where the tutorial i look at us the GetAssemblyIdentity but where i do not see how im supposed to do this for my app quz its not a console app! the tutorial im looking at is this https://www.youtube.com/watch?v=6Yf-eDsRrnM and at time stamp 1h 28 min he starts looking at assembly versions and how to get them for your installer but i do not really understand how to do this with a wpf app. what i have tried this far is
<Target Name="BeforeBuild">
<GetAssemblyIdentity AssemblyFiles="..\WPFAPP\bin\$(C)">
</GetAssemblyIdentity>
</Target>
<Target Name="AfterBuild">
WPFAPP is a placeholder for my app.
FIRST SOLUTION:
You can use $(MSBuildProjectName)
So, specify
<TargetName>$(ProjectName)</TargetName>
In your *.csproj
And then you can use $(MSBuildProjectName) as Assembly name.
To get access to this variable you should write in wixproj
<Target Name="BeforeBuild">
<PropertyGroup>
<DefineConstants>ProjectName=%(MSBuildProjectName)</DefineConstants>
</PropertyGroup>
</Target>
List of availables variables you can see here
https://learn.microsoft.com/en-us/visualstudio/msbuild/msbuild-reserved-and-well-known-properties?view=vs-2019
SECOND SOLUTION:
So, if you want to use versions. See example here.
<Target Name="BeforeBuild">
<GetAssemblyIdentity AssemblyFiles="..\MyApp\bin\$(Configuration)\MyApp.exe">
<Output TaskParameter="Assemblies" ItemName="AssemblyVersion" />
</GetAssemblyIdentity>
<PropertyGroup>
<DefineConstants>BuildVersion=%(AssemblyVersion.Version)</DefineConstants>
</PropertyGroup>
</Target>
You should specify Assembly file (dll and exe files is both files of .Net and .exe file can be specified here too).
Then you can use BuildVersionVariable like here:
<Product Id="*"
Name="WixProject1"
Language="1033"
Version="$(var.BuildVersion)"
Manufacturer="WixProject1"
UpgradeCode="c93e09b9-9e8f-444c-a35b-84beb2c3788f">
...
</Product>
p.s. You can combine this approaches and get some info from one path and some info from another. The main IDEA to define constants in project file and then get acces s to it from WIX
I have a WinForms application which I am publishing via ClickOnce. This applciation includes the Accord FFMPEG libraries, which are included as references.
The FFMPEG NuGet package folder includes a .targets file, which includes a variety of dlls needed for proper operation of the FFMPEG library (avcodec.dll, avformat.dll, avutil.dll). These are copied to the \bin folder when building the project. This is done by including this line in the .csproj:
Import Project="..\packages\Accord.Video.FFMPEG.3.3.0\build\Accord.Video.FFMPEG.targets" Condition="Exists('..\packages\Accord.Video.FFMPEG.3.3.0\build\Accord.Video.FFMPEG.targets')"
However when publishing the application via ClickOnce, these files are not included in the published folder. Is there a way to run the Import Project task and add the files into the published folder?
Unfortunately I didn't manage to get this working using the .targets file. My solution in the end was to copy the required dlls to the deployment folder and include them in the manifest, as below.
<ItemGroup Label="FFMPEG DLL">
<ClickOnce Include="..\packages\Accord.Video.FFMPEG.3.3.0\build\*.dll">
<InProject>false</InProject>
<Visible>false</Visible>
</ClickOnce>
</ItemGroup>
<Target Name="BeforeBuild">
<CreateItem Include="#(ClickOnce)" AdditionalMetadata="TargetPath=%(FileName)%(Extension);IsDataFile=false">
<Output TaskParameter="Include" ItemName="_DeploymentManifestFiles" />
</CreateItem>
</Target>
<Target Name="BeforePublish">
<Touch Files="#(IntermediateAssembly)" />
</Target>
This is using .NET 4.6.1 and VS2017.
Once my nant build has completed I'd like to rename the generated .exe file using a post-build command which is appended to the end of the projects .csproj file (within the Project element):
<Target Name="AfterBuild">
<Copy SourceFiles="$(TargetDir)\$(TargetName).exe" DestinationFiles="$(TargetDir)\MyApplication-$(AssemblyFileVersion).exe" SkipUnchangedFiles="true" />
</Target>
As you can see above, I am trying to rename the executable to: MyApplication-$(AssemblyFileVersion).exe however, this is obviously wrong, as the resulting executable is simply named: MyApplication-.exe (so the version I am trying to add at the end of the file name is missing).
I have defined the AssemblyFileInfoVersion in the AssemblyInfo.cs file as follows:
[assembly: AssemblyFileVersion("1.5.1")]
So the question is: How can I access the AssemblyFileVersion in the csproj file of that same project?
GetAssemblyIdentity can get information about complied assemblies. The task output contain metadata entries about Version, PublicKeyToken, and Culture.
I used $(TargetDir)\$(TargetName).exe as the assembly file.
<ItemGroup>
<AssembliesPath Include="$(TargetDir)\$(TargetName).exe" />
</ItemGroup>
<Target Name="GetAssemblyInfo">
<GetAssemblyIdentity AssemblyFiles="#(AssembliesPath)">
<Output TaskParameter="Assemblies" ItemName="AssemblyInfo"/>
</GetAssemblyIdentity>
</Target>
And then:
<Target Name="AfterBuild">
<GetAssemblyInfo />
<Copy SourceFiles="$(TargetDir)\$(TargetName).exe" DestinationFiles="$(TargetDir)\MyApplication-%(AssemblyInfo.Version).exe" SkipUnchangedFiles="true" />
</Target>
The following code is from ISun's original answer and this is actually how I ended up doing it in the end, as I had problems defining a custom task (ms build references were constantly auto-kicked and the build kept failing over and again).
As you can see from the comments under ISun's answer I always got the version 0.0.0.0 - despite having changed the version for AssemblyFileVersion and AssemblyVersion to 1.0.0.0 by manually opening the AssemblyInfo.cs in a texteditor. I later read how to edit the AssemblyInfo.cs from my Visual Studio, here is how:
Right-click on your project (that generates the exe file)
Click on Properties
Open the Application tab (first tab on the left) on the window that'll open
You'll see fields for setting the Assembly name, Default namespace etc however to edit the
AssemblyInfo.cs, simply click on the Button called Assembly Information to the right
And for some reason - I have no clue why it suddenly worked, after I had put in all the information via the above method (using Visual Studio) ! When I first opened the AssemblyInfo.cs using the above way, all my fields were actually empty, despite them being filled in the actual file.
And now that I got the AssemblyInfo.cs to finally function correctly, I used ISun's original code to achieve my goal. By adding the following snippet just before the closing tag in my project's .csproj file:
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<Target Name="AfterBuild">
<GetAssemblyIdentity AssemblyFiles="$(TargetDir)\$(TargetName).exe">
<Output TaskParameter="Assemblies" ItemName="AssemblyInfo"/>
</GetAssemblyIdentity>
<Copy SourceFiles="$(TargetDir)\$(TargetName).exe" DestinationFiles="$(TargetDir)\MyApplication-%(AssemblyInfo.Version).exe" SkipUnchangedFiles="true" />
</Target>
I am using msbuild.exe to automate my build from the command line.
I do the following steps.
Compile projects into a folder each outside the project directory
zip every compiled project
here are my targets
first one to compile
<Target Name="BuildProjects" DependsOnTargets="BeforeBuild">
<ItemGroup>
<BuildProjectFiles Include="**\MyCompany.Project1\MyCompany.Project1.csproj" />
<BuildProjectFiles Include="**\MyCompany.Project2\MyCompany.Project2.csproj" />
<BuildProjectFiles Include="**\MyCompany.Project2\MyCompany.Project2-CE.csproj" />
... and some more
</ItemGroup>
<MSBuild Projects="#(BuildProjectFiles)" Properties="AllowUnsafeBlocks=true;Configuration=$(Configuration);OutputPath=$(MSBuildProjectDirectory)\Deploy\bin\%(BuildProjectFiles.FileName)">
<Output TaskParameter="TargetOutputs"
ItemName="BuildProjectsOutputFiles" />
</MSBuild>
</Target>
and now the target to zip every compiled project to its one file.
<Target Name="ZipProjects" DependsOnTargets="BuildProjects">
<CreateItem
Include="#(BuildProjectOutputFiles)"
AdditionalMetadata="AssemblyName=%(Filename);ProjectName=%(RelativeDir)">
<Output TaskParameter="Include" ItemName="BuildProjectsOutputFiles123"/>
</CreateItem>
<CreateItem Include="%(BuildProjectsOutputFiles123.RelativeDir)*" AdditionalMetadata="OutputFileName=$(MSBuildProjectDirectory)\Deploy\dist\$(Configuration)\%(BuildProjectsOutputFiles123.AssemblyName)-$(MajorNumber).$(MinorNumber).$(ReleaseNumber).zip;WorkingDirectory=%(BuildProjectsOutputFiles123.RelativeDir)">
<Output TaskParameter="Include" ItemName="BuildProjectsOutputFiles456"/>
</CreateItem>
<Zip Files="#(BuildProjectsOutputFiles456)"
WorkingDirectory="%(BuildProjectsOutputFiles456.WorkingDirectory)"
ZipFileName="%(BuildProjectOutputFiles456.OutputFileName)" />
<!-- ZipLevel="9"/> -->
</Target>
So what happens is that every project I specified in BuildProjectFiles gets compiled into the folder <rootdir>\deploy\bin\<name of the csproj file without extension\
In the second step I use the MSBuild.Community.Tasks Zip-Task to zip every project and copy it to <rootdir>\deploy\dist\release\<assemblyname>-<version>.zip
So basically the assembly project1.exe and its dependencies are in the file project1-2.4.7.zip after executing msbuild.
That works very well. But now I have a change that I can't figure out how solve. I have two assemblys with the same assembly name (one for Windows and the other for Windows CE) so the first project compiles and creates a folder project2-2.4.7.zip and then the next project compiles and overwrites the zip file.
Now I want the Zip-File to be named after the .csproj file (like the bin folder).
Since my one project file is called mycompany.project2.csproj and the other one mycompany.project2-ce.csproj I should be fine.
In short: How can I pass the project name to the zip target?
Is this suitable?
$(MSBuildProjectName)
MSBuild Reserved Properties
I'm trying to update my (previously working) pdf-creating web application to use the ABCpdf.NET and ABCpdf.NET Gecko Runtime nuget packages.
I've installed both packages (both are version 8.1.1.6) however when I run my application, I get the following WebSupergoo.ABCpdf8.Internal.PDFException:
Failed to add HTML: Gecko engine hit an error it was unable to recover
from. Possible causes: XULRunner folder is corrupt or is from another
version of ABCpdf.
After installing the ABCpdf.NET Gecko Runtime package, I got a dialog telling me that I would need to manually copy the XULRunner folder into my output directory. In order to achieve this, I added the following to my applications .csproj file:
<Target Name="AfterBuild">
<CallTarget Targets="CopyAbcpdfToDeployFolder" />
</Target>
<Target Name="CopyAbcpdfToDeployFolder">
<ItemGroup>
<SourceDir Include="$(ProjectDir)XULRunner\**\*.*" />
</ItemGroup>
<Copy SourceFiles="#(SourceDir)" DestinationFolder="$(WebProjectOutputDir)\$(OutputPath)%(SourceDir.RecursiveDir)\XULRunner" />
</Target>
(This seems to be working correctly - the XULRunner folder and its contents are present in my bin folder after a build)
The line of code that is failing is as follows:
theDoc.AddImageUrl(url);
Can anyone help me get this working?
As it turns out, my changes to the .csproj file we not copying all files into the correct subfolders. In order to copy the folder structure and files recursively, the XML should have looked like this:
<Target Name="AfterBuild">
<CallTarget Targets="CopyXULRunnerToDeployFolder" />
</Target>
<Target Name="CopyXULRunnerToDeployFolder">
<ItemGroup>
<MyFiles Include="XULRunner\**\*.*" />
</ItemGroup>
<Microsoft.Build.Tasks.Copy SourceFiles="#(MyFiles)" DestinationFiles="#(MyFiles->'$(OutputPath)\XULRunner\%(RecursiveDir)%(Filename)%(Extension)')"/>
</Target>
I was able to accomplish the same outcome with the following MSBuild xml:
<ItemGroup>
<Content Include="XULRunner\**\*.*">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
</ItemGroup>
I fell upon this setup after dealing with issues concerning the building of a package via MSDeploy not including the XULRunner files.
Not sure if there's anything patently wrong with this, but so far it works for me on a multiple staged deployment setup.