Getting assembly version of WPF - c#

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

Related

Wix Toolset how to copy to folder with version in path

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.

Make VisualStudio run a command to generate C# code

I'm trying to do something extremely simple, yet despite hours of scouring the Internet and desperately typing in every tiny example fragment I can find, I literally cannot make VS do what I want. Seriously frustrated here!
This is what I want:
When I do a build, I want VS to find every *.fubar file in the project.
For each *.fubar file, I want VS to execute fubar.exe with the input file as argument.
I want VS to compile the resulting *.cs files as usual.
I am damn-well convinced it must be possible to achieve this trivially simple task. I just need to figure out how.
So that's the problem. Let me explain what I've researched so far.
It seems that you can write a VS extension by implementing some COM interface. But that requires you to edit the Registry to tell VS where the plugin is. Obviously that's completely unacceptable; I should not have to reconfigure the OS just to run a command-line tool!
It appears that MSBuild is supposed to be this ultra-configurable build management tool where you can define an arbitrary set of build steps and their interdependencies. It seems like it should be trivial to add an extra task before the build C# compilation step that runs fubar.exe to generate the source code. And yet, after hours of trying, I cannot get a single C# file to appear.
Some documents talk about special pre-build and post-build steps. But it seems silly to need a special hook when the number and order of build steps is supposed to be arbitrary to begin with. Regardless, I tried it, and it still didn't work.
To be clear: Playing around with the project file makes VS display the item properties slightly differently, and doesn't make the build fail. But it also doesn't ever make any C# files appear. (At least, I can't find them anywhere on the disk. I can't tell if my tool is actually being run or not — I suspect "not".)
Can anybody tell me how to make this trivial, trivial thing work? There must be a way!
I agree that T4 may be a prettier solution, but the below MsBuild code works.
You can create a custom targets file that does the calling, I created one that simply copies files, but the process should be similar for invoking your executable.
Make sure you set your FuBar files to BuildAction "Fubars". The Build action has been defined in the targets file using the "AvailableItemName" property.
You may need to extend the below script with a couple of Conditions and Exists checks to make sure it runs when needed. I called it convert.targets and places it in the project directory.
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<!-- Ensure Visual Studio puts the FuBars item in the Build Action dropdown -->
<ItemGroup>
<AvailableItemName Include="FuBars" />
</ItemGroup>
<!-- Execute action on all items matching FuBar (only if output is missing or input has changed) -->
<Target Name="GenerateCodeFubar" Inputs="#(Fubars)" Outputs="$(MSBuildProjectDirectory)/obj/$(Configuration)/Fubars/%(Fubars.Identity).g.cs" >
<MakeDir Directories="$(MSBuildProjectDirectory)/obj/$(Configuration)/Fubars/%(Fubars.RelativeDir)" />
<Exec Command="cmd /c copy "%(FuBars.FullPath)" "$(MSBuildProjectDirectory)/obj/$(Configuration)/Fubars/%(FuBars.Identity).g.cs""/>
</Target>
<!-- Pick up generated code in the Compile group. Separated from the execute action so that the previous action only runs when files have changes -->
<Target Name="IncludeCodeFubarInCompile">
<ItemGroup>
<GeneratedFubars Include="$(MSBuildProjectDirectory)/obj/$(Configuration)/Fubars/%(FuBars.Identity).g.cs"/>
</ItemGroup>
<CreateItem Include="%(GeneratedFubars.FullPath)">
<Output TaskParameter="Include" ItemName="Compile" />
</CreateItem>
</Target>
<!-- Clean up for Rebuild or Clean -->
<Target Name="DeleteCodeFubar">
<RemoveDir Directories="$(MSBuildProjectDirectory)/obj/$(Configuration)/Fubars/" />
<Delete Files="$(MSBuildProjectDirectory)/obj/$(Configuration)/fubars/**/*.g.cs" />
</Target>
<!-- Instruct MsBuild when to call target on Build-->
<PropertyGroup>
<BuildDependsOn>
GenerateCodeFubar;
IncludeCodeFubarInCompile;
$(BuildDependsOn);
</BuildDependsOn>
</PropertyGroup>
<!-- Instruct MsBuild when to call target on Clean-->
<PropertyGroup>
<CleanDependsOn>
DeleteCodeFubar;
$(CleanDependsOn);
</CleanDependsOn>
</PropertyGroup>
</Project>
Include it in your .csproj after the import the last targets file:
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- IMPORT HERE -->
<Import Project="convert.targets" />
<!-- END: IMPORT HERE -->
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
-->
</Project>
You may have to tell Visual Studio to turn off the Host Compiler, as Visual Studio caches the contents of the <Compile> group for performance. Though a quick test shows this may not be needed.
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<!-- The first property group should not have any condition on it -->
<PropertyGroup>
<!-- Include below item in the first PropertyGroup item:
<UseHostCompilerIfAvailable>FALSE</UseHostCompilerIfAvailable>
</PropertyGroup>
This is extremely easy.
In your project properties select the Build Events tab and enter a correct Pre-build event command line.
Without knowing what footer.exe is nor its command line args, I can't give you any specific help for that app. But there is a "Macros" button on the pre-build event dialog that can help you with various substitution variables.
Additionally, VS comes with the T4 templating system which might be a better fit than whatever footer.exe is.

Reference AssemblyFileVersion in csproj file

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>

MSBuild task does not cause generated c# files to compile

I've been trying to write an MSBuild task to "compile" CoCo/R .ATG files into C# files which will then get compiled into the executable, this is to replace the pre-build event.
I've managed to get the .ATG -> .cs process working, however something is not right since the generates .cs files do not get compiled.
If I then modify the .ATG file again, the "old" .cs files seems to get compiled then new ones generated.
I'm quite sure I'm missing something that will inform the rest of the build process that these files have changed.
Here is the target definition that I have included in my Visual Studio 2010 project.
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<AvailableItemName Include="BuildATG" />
</ItemGroup>
<PropertyGroup>
<CoreBuildDependsOn>
BuildATGTarget;
$(CoreBuildDependsOn)
</CoreBuildDependsOn>
</PropertyGroup>
<Target Name="BuildATGTarget" Inputs="#(BuildATG)" Outputs="#(BuildATG -> '%(RelativeDir)Parser.cs')">
<Exec Command="Coco.exe %(BuildATG.Identity)" Outputs="%(BuildATG.RelativeDir)Parser.cs" />
</Target>
</Project>
I am completly new to MSBuild, so any advice / pointers would be appreciated.
One possible solution I have found is to do the following changes and add an ItemGroup inside the target.
<Target Name="BuildATGTarget" Inputs="#(BuildATG)" Outputs="#(BuildATG -> '%(RelativeDir)Parser.cs')">
<Exec Command="Coco.exe %(BuildATG.Identity)" Outputs="%(BuildATG.RelativeDir)Parser.cs" />
<ItemGroup>
<Compile Include="%(BuildATG.RelativeDir)Parser.cs" />
<Compile Include="%(BuildATG.RelativeDir)Scanner.cs" />
</ItemGroup>
</Target>
To avoid duplicate files in your build, you also need to mark the files (Parser.cs and Scanner.cs) in the Visual Studio 2010 project with Build Action: None

MSBuild Task from .csproj File

I Am trying to add a Post Build MSBuild event to my csproj to do this i am trying to call an MSBuild task from inside the Afterbuild target in the.csproj file
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.-->
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
<Message Text="Copying Files" />
<MSBuild Projects="post.build"
Targets="Copy"
ContinueOnError="false" />
</Target>
This is then the post.build file.
<Project DefaultTargets="Copy"
xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Target Name="Copy">
<Message Text="Copying Files inside COPY" />
<CallTarget Targets="CopyToProfile"/> </Target>
</project>
It seems that the csproj cannot call the MSbuild task, can anyone suggest what might be going wrong here. I get the error
error MSB4057: The target "Copy" does
not exist in the project.
So What I eventually got working was.
I did as Martin Suggested and
<Import Project="post.build"/>
However the MSBuild Task still did not function as planned. So I ended up using the
<CallTarget Targets="copy"/>
To Call across the files. This sounds like it is a limitation in VS2008 and is fixed in VS2010.
Are you sure you haven't made the typo in your actual post.build file as well? That is, it should be not . XML is case-sensitive.
Also, I would double-check that the post.build file is placed in the same folder as the .csproj file.

Categories

Resources