C# Visual Studio Project Properties & MSBuild Macros - c#

Why can't I use MSBuild macros in a C# Project's properties? These all work find in a CPP project.
For example:
Create an empty C# console application
Change the main method to take command line arguments
Right click on the project in solution explorer and click properties
Choose "Debug" on the left side
In Command Line Argument's, enter: "$(SolutionDir)"
Debug your program
Notice that the argument is quite literally $(SolutionDir) rather than what it translates to.
I have the same problem with "Xml documentation file path" and other fields.

Why can't I use MSBuild macros in a C# Project's properties? These all work find in a CPP project.
This is because the way C# and CPP project introduce macros is not the same.
For C# project, it introduced by the .props, .targets files, for example, the Microsoft.CSharp.targets file. In your project file .csproj you will find following Import:
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
For CPP project, it introduced by property sheets, you can get it from View->Other Windows->Property Manager, which is not supported by C# project.
The different:
You can use property sheets to create project configurations that can
be applied to multiple projects since project settings that are
defined in .vsprops files are inheritable, unlike project settings
defined in Project Files (.vcproj files). Therefore, a project
configuration defined in a .vcproj file can inherit project settings
from one or more property sheets (.vsprops files). For more
information, see Property Inheritance.
That the reason why you can use MSBuild macros in a CPP Project's properties but not in C# project.
You can check following document for some more details:
Common macros for build commands and properties
Property Sheets (C++)
Hope this helps.

Related

How to invoke a target of a msbuild project without recursively calling the same target on sub projects

I created bunch of targets in msbuild project. Lets call this project TopLevelProject. Lets say this has a target called CollectNZip. TopLevelProject depends on SubProjectA, SubProjectB and SubProjectC.
I have a solutions targets file Directory.Solution.targets that contains all the projects below its folder including TopLevelProject.
As part of a target in this file say BuildAll, I like to invoke CollectNZip target of TopLevelProject. So I added TopLevelProject:CollectNZip as dependency.
When I invoke BuildAll, I do see TopLevelProject is invoked with target CollectNZip. But this sucker as part of dependency started invoking SubProjectA:CollectNZip, SubProjectB:CollectNZip etc. As those sub projects don't have CollectNZip, the buildall target is failing.
What is the trick to invoke a target of a project, but don't invoke the sub projects as part of the invocation?
If I understand the scenario:
There is a solution file with a set of projects. Let's say the solution is named 'MySolution.sln'.
I assume the solution file was created by either Visual Studio or the dotnet tool.
The set of projects in the solution include: 'TopLevelProject.csproj', 'SubProjectA.csproj', 'SubProjectB.csproj', and 'SubProjectC.csproj'.
I assume the project files were created as C# projects by either Visual Studio or the dotnet tool.
The project 'TopLevelProject' has ProjectReferences to 'SubProjectA', 'SubProjectB', and 'SubProjectC'.
The project 'TopLevelProject' also has a target named 'CollectNZip'.
There is a 'Directory.Solution.targets' file that is a peer of 'MySolution.sln' or in a parent directory.
'Directory.Solution.targets' contains a 'BuildAll` target.
The 'Directory.Solution.targets' file is ignored by Visual Studio so the 'BuildAll' target is only available when running from the command line.
Projects can be added to a solution file (SLN) but can't be added to an MSBuild file. The 'Directory.Solution.targets' file is an MSBuild file. It can't be a container for projects. I don't know what the following statement means:
I have a solutions targets file Directory.Solution.targets that contains all the projects below its folder including TopLevelProject.
Note that the Import element is a textual include. It doesn't "add" a project; it adds the content of the file in the Project attribute into the content of the current project.
From the command line, you can invoke the 'CollectNZip' target of project 'TopLevelProject' via the solution file.
e.g.
msbuild MySolution.sln /t:TopLevelProject:CollectNZip
This will invoke only the 'CollectNZip' target on only the TopLevelProject project. It will not run other projects from the solution.
I don't know what the following statement means:
As part of a target in this file say BuildAll, I like to invoke CollectNZip target of TopLevelProject. So I added TopLevelProject:CollectNZip as dependency.
The <ProjectName>:<TargetName> syntax is supported for the command line /target switch. It is not supported within the code of an MSBuild file. TopLevelProject:CollectNZip can't be a dependency of a target.
MSBuild doesn't have any notion of "sub projects" although there are two mechanisms which can add dependencies between projects.
A project dependency can be added to the solution file. The solution level project dependency effects the build order -- and does nothing else. It does not share files.
A ProjectReference can be added to a project file. The ProjectReference is an ItemGroup and is part of the C# project build system that is built on the general MSBuild build engine. ProjectReference is specific to certain targets of the C# build system, most importantly the build and clean targets. build and clean will evaluate the ProjectReference ItemGroup, will run the referenced projects, and on a build will copy in the product of the referenced project.
If I add a target named 'Fred' to all the projects and I invoke 'Fred' on one project via the solution, 'Fred' will not be called on projects in the ProjectReference ItemGroup.
A project is an encapsulation. It doesn't know its 'caller' and, excepting ProjectReference, it doesn't know about other projects.
The described behavior is not how MSBuild works and I'm guessing that the description is imprecise and/or there is pertinent code not shown.
If 'CollectNZip' should only run within the 'TopLevelProject' project, then only add the target to that project. If you want to be able to build with and without 'CollectNZip', define a property that can be used as a flag, e.g. add an 'EnableCollectNZip' property and add a Condition on the target that tests the value of the 'EnableCollectNZip' property.

DllImport from c# project to c++ project in same solution

I have a solution with two projects:
C# console application (.NET Core 3.1)
and C++ Dynamic Library (.dll)
I need to call the C++ DLL from the C# project, using DllImport. When I provide the full path of the DLL, the application finds it. But I want to replace the path with a relative path, and I can't figure out how to do it.
First of all, make the C++ project a dependency of the C# project. This ensures that the C++ project will be built before the C# project if it's outdated. You can set the project dependencies in the solution settings.
Now that we ensured that the dll is always up to date, we have to somehow get it in the same directoy as the C# executable. We have two options:
a post build command to copy the dll to the output directory of the C# project, or
we set the output directory of both projects to the same directory.
Post build event
We can simply use a copy command. Go to C++ project settings > Build Events > Post-Build Event and copy the following command to to the Command Line field:
xcopy /y "$(OutDir)*.dll" "$(SolutionDir)MY_CSHARP_PROJECT_NAME\bin\$(Platform)\$(Configuration)"
Replace MY_CSHARP_PROJECT_NAME with the name of your C# project. I'm using the default paths here, depending on your solution you might have to tweak the paths a bit.
Shared build directory
I wouldn't recommend this one, because you can run into trouble with it.
Go to the Build tab in the project settings of your C# project.
At the top of the page select Debug as configuration.
At the bottom of the page change Output path to match the C++ output directory for Debug builds (this one is usually in the same folder as the solution file).
Repeat 2 and 3 but this time with Release instead of Debug.

Custom build action properties in a Visual Studio C# project

In a Visual Studio C++ project I can define custom build actions and corresponding property rules (see cl.xml under the MSBuild folder). How can I create such a rule for a custom build action in a C# project? Under the MSBuild folder there's a the file Microsoft.CSharp.CurrentVersion.targets which references CSharp.ProjectItemsSchema.xaml, CSharp.xaml and CSharp.BrowseObject.xaml which looks exacltly like the definitions I need. Using procmon I can see that these files are not accessed at all. What's the correct way to define custom build actions?
To clarify what I want to accomplish here's an example:
I add an image file (.png) to the project
I have a special image resource 'compiler' the transform the image (this compiler is defined using a msbuild target)
I want to change properties of the image file (e.g. target resolution, format, etc.). In a C++ project I can open the file property dialog for this.
These properties are saved as MSBuild item metadata and forwarded to the MSBuild target.
The resulting project file would contain data like this:
<ItemGroup>
<MyImageContent Include="Image.png">
<OutputName>MyImage.png</OutputName>
<TargetResX>512</TargetResX>
<TargetResY>256</TargetResY>
</MyImageContent>
</ItemGroup>
This additional metadata can easily be used by a custom MSBuild target. So far I know how to do it.
But: In a VC++ project this metadata can be easily edited in a property window provided by Visual Studio. The definition Visual Studio uses comes from a rules xml file similar to the cl.xml I mentioned. How can I accomplish this in a C# project?
What's the correct way to define custom build actions?
You can use the MSBuild Targets or imported .targets file to define custom build actions in the project file.
1.I add an image file (.png) to the project
For this build action, you can use a copy task in the target to copy the image file to the project folder:
<Target Name="CopyFiles">
<Copy
SourceFiles="#(MySourceFiles)"
DestinationFolder="c:\MyProject\Destination"
/>
</Target>
2.I have a special image resource 'compiler' the transform the image (this compiler is defined using a msbuild target)
For this build action, you can import that msbuild target.
3.I want to change properties of the image file.
In the C# project, the properties of the image are also saved as MSBuild item metadata and forwarded to the MSBuild target.
Update:
In a VC++ project this metadata can be easily edited in a property window provided by Visual Studio. The definition Visual Studio uses comes from a rules xml file similar to the cl.xml I mentioned. How can I accomplish this in a C# project?
As far as I know we could not make custom items have additional metadata which be editable in the property window. This only can be applied to C++ and C++/CLI projects. .NET projects (C# and Visual Basic) don’t have that many options to be tweaked. You can refer to the Sharing Project Properties in Visual C++ for more detail.
Hope this can help you.

Copy C++ library to a C# project automatically on build? (Visual Studio 2010)

I have a library written in C++, and a wrapper for this library written in C#.
Both projects are under development, and the way it is now I have to manually copy the .dll from the C++ project to the C# project after each build.
So I was wondering if there was any way to make Visual Studio copy the .dll from the C++ project automatically when re-building?
You can use Build events in visual studio and place a dos command to copy the dll to the current project
Right click on the project in Solution explorer in Visual studio, select properties. There in Build events you can type:
copy c:\Cplusproject\yourproject.dll $(TargetDir)
You can use Post Build or Pre Build events based on your requirements
See this article: http://geekswithblogs.net/dchestnutt/archive/2006/05/30/80113.aspx
Use post build event for that. Just something like xcopy <yourDllFilePath> <destinationPath> and it will copy your dll file to wherever your want
if yr using that c++ dll as reference, then u might be able to add the c++ project as a project reference, and everything will be copied automaticly, and it also helps while debugging.
Click on references in yr c# project, then a dialog window opens and choose Projects and select yr c++ project
There are several approach to achieve what you request.
Here I suppose you are using Microsoft Visual C++, but on other platforms there will be analogous functionalities.
Right click on the icon representing the vc++ project on the Solution explorer
Click Properties
Select the Configuration Properties/Build Events/Post Build Event node
Write the Command Line required to copy the dll around
Remember you must do it for every Configuration and for every Platform supported from your project.
Alternatively you may ask the Linker to output directly on the location referenced by your C# project:
Right click on the icon representing the vc++ project on the Solution explorer
Click Properties
Select the Configuration Properties/Linker/General Event node
Set the Output File property to the location referenced by your C# project
That said, you may also get the dll from the c# project.

Is there an equivalent to the "Property Manager" for C# projects (for common project settings)?

You can use the Property Manager window in Visual Studio for managing common properties of C++ projects, but there appears to be no equivalent to this for C# projects.
Is there a way to set common settings across multiple projects? Examples of things I'd like to do:
add TEST preprocessor directive for all projects that have a TEST build configuration
change warnings to errors for all C# projects
add a reference to some common assembly for N selected C# projects at once
etc.
A plugin, macro, or extension would all be acceptable.
You can customize the C# project template for Visual Studio, so that every time you create a new project it has all the settings you want.
http://msdn.microsoft.com/en-us/library/6db0hwky.aspx
http://www.a2zdotnet.com/View.aspx?Id=170
The closest equivalent is currently using regex from within VS on an unloaded project or writing something to process the msbuild xml backing the .csproj files.
There is no a real equivalent of Property Manager for C# projects.
However, if the goal is to share common settings across multiple projects, you can create a NuGet package with .props file defining the shared properties and reference it in your C# projects - VS will automatically import it at build time.
.props and .targets inclusion is supported as of NuGet 2.x.
Tip: make sure the .props file name matches the NuGet package id, otherwise it won't be included.
You can see an example here.

Categories