Yes it is you say. Well you can do this:

msbuild mysolution.sln

and it does work. It will build all of your solution but it is not a true MsBuild file in the MsBuild format. The MSBuild engine has special code to deal with them. What it is actually doing is transforming the solution into a MsBuild file and running that.

Before you run it try this at the command prompt:

Set MSBuildEmitSolution = 1

This sets a special environment variable that MSBuild checks, if its set then it emits a copy of the transformed solution. Open this up and you will see what is happening when your build your solution. Its not very complicated, mainly just a bunch of calls to the MSBUILD task for the projects in the solution.

MSBuild Transforms

November 4, 2007

Passing a list of items to a task is pretty straightforward in MSBuild. Consider a simple itemgroup which contains a bunch of files.

<ItemGroup>
    <MyFiles Include="C:\Windows\Microsoft.NET\Framework\v2.0.50727\1033\*"/>
</ItemGroup>

We can call a task and pass our files as a list using @(MyFiles).

<Message Text="@(MyFiles)"/>

Target Build:
    C:\Windows\Microsoft.NET\Framework\v2.0.50727\1033\alinkui.dll;C:\Windows\Mi
crosoft.NET\Framework\v2.0.50727\1033\cscompui.dll;C:\Windows\Microsoft.NET\Fram
ework\v2.0.50727\1033\CvtResUI.dll;C:\Windows\Microsoft.NET\Framework\v2.0.50727
\1033\vbc7ui.dll;C:\Windows\Microsoft.NET\Framework\v2.0.50727\1033\vjscui.dll;C
:\Windows\Microsoft.NET\Framework\v2.0.50727\1033\vjslibui.dll;C:\Windows\Micros
oft.NET\Framework\v2.0.50727\1033\Vsavb7rtUI.dll
    alinkui;cscompui;CvtResUI;vbc7ui;vjscui;vjslibui;Vsavb7rtUI

Build succeeded.
    0 Warning(s)
    0 Error(s)

We may not always want to pass in the full file name and path, what we might want to pass is item metadata. This is where MSBuild transforms come in. They let us change which pieces of information are used in the construction of the list. The syntax takes the form of @(itemgroup->’%(itemmetadata)’)

We can pass a just the file names (no extension) taken from the FileName well known item metadata.

<Message Text=@(MyFiles->’%(FileName)’)/>

alinkui;cscompui;CvtResUI;vbc7ui;vjscui;vjslibui;Vsavb7rtUI

or the file name and extension

<Message Text="@(MyFiles->'%(FileName)%(Extension)')"/>

alinkui.dll;cscompui.dll;CvtResUI.dll;vbc7ui.dll;vjscui.dll;vjslibui.dll;Vsavb7rtUI.dll

or we might want to pass the list of files but with a different extension.

<Message Text="@(MyFiles->'%(FileName).data')"/>

alinkui.data;cscompui.data;CvtResUI.data;vbc7ui.data;vjscui.data;vjslibui.data;Vsavb7rtUI.data

MSBuild tasks can handle a list of files in several ways. Many of them will take them all in one go, through a single attribute. The list comes through as ITaskItem[] inside the task itself. We may not always want to call the task in this way, and not all support this. In some scenarios we might want to call the task once for each file.

Lets start by creating an itemgroup that defines all our files. Were going to give it the Name MyFiles and we’ll use a wildcard on the include attribute to select all the files in a directory.

<ItemGroup>
    <MyFiles Include="C:\Windows\Microsoft.NET\Framework\v2.0.50727\1033\*"/>
</ItemGroup>

A lot of targets in MSBuild can take a list seperated by semicolons. the CSC task for the C# compiler can take a list of source files in this way. To pass our list of files in this way we use the @(itemgroup) syntax, like this:

<Message Importance="normal" Text="@(MyFiles)"/>

In this example with the message task we our passing a single string with all our filenames seperated by semicolons.

Often what we actually want to do is call the task once for every file in the itemgroup. To do this we use the %(itemgroup.itemmetadata) syntax. In our itemgroup we haven’t defined any item metadata, fortunately msbuild provides some well known item metadata for us automatically. This includes such things as the file name, path, extension.

<Message Importance="normal" Text="%(MyFiles.FullPath)"/>        

Here we will call the message task once for every file and we will pass the full path.

The whole msbuild file:

<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
    <ItemGroup>
        <MyFiles Include="C:\Windows\Microsoft.NET\Framework\v2.0.50727\1033\*"/>
    </ItemGroup>

    <Target Name="Build">
        <!--Pass all in one call ';' seperated-->
        <Message Importance="normal" Text="@(MyFiles)"/>

        <!--Call Target once for each file-->
        <Message Importance="normal" Text="%(MyFiles.FullPath)"/>
    </Target>
</Project>

When we run it with msbuild, we firstly get the output from the first call to the message task which received the text as a single string seperated by ‘;’. After this we have the output where it called the message target once for each file.

__________________________________________________
Project “C:\Temp\multiple.xml” (default targets):

Target Build:
    C:\Windows\Microsoft.NET\Framework\v2.0.50727\1033\alinkui.dll;C:\Windows\Mi
crosoft.NET\Framework\v2.0.50727\1033\cscompui.dll;C:\Windows\Microsoft.NET\Fram
ework\v2.0.50727\1033\CvtResUI.dll;C:\Windows\Microsoft.NET\Framework\v2.0.50727
\1033\vbc7ui.dll;C:\Windows\Microsoft.NET\Framework\v2.0.50727\1033\vjscui.dll;C
:\Windows\Microsoft.NET\Framework\v2.0.50727\1033\vjslibui.dll;C:\Windows\Micros
oft.NET\Framework\v2.0.50727\1033\Vsavb7rtUI.dll

    C:\Windows\Microsoft.NET\Framework\v2.0.50727\1033\alinkui.dll
    C:\Windows\Microsoft.NET\Framework\v2.0.50727\1033\cscompui.dll
    C:\Windows\Microsoft.NET\Framework\v2.0.50727\1033\CvtResUI.dll
    C:\Windows\Microsoft.NET\Framework\v2.0.50727\1033\vbc7ui.dll
    C:\Windows\Microsoft.NET\Framework\v2.0.50727\1033\vjscui.dll
    C:\Windows\Microsoft.NET\Framework\v2.0.50727\1033\vjslibui.dll
    C:\Windows\Microsoft.NET\Framework\v2.0.50727\1033\Vsavb7rtUI.dll

Build succeeded.
    0 Warning(s)
    0 Error(s)

Time Elapsed 00:00:00.05

Being a proud owner of a Canon EOS 5D one of the first things I did after getting a new 64bit Vista machine was to go get the imaging codec from Canon for their digital SLR’s.

My enthusiasm was quickly destroyed when I found out that it was 32bit only. Fast forward a few months and Canon have just released a new version of the Codec that adds support for the likes of the 1D Mark III. But still no Vista 64 support. Come on Canon, sort this out. You’ve gone to the effort to write the codec, spend a little bit more effort to create a 64bit version. As our favourite pub land-lord would say: Shame on you Canon, Shame on you.

Here’s hoping you fix this for the next version.

Oh, and its not just Canon that doesn’t know Vista 64 bit exists, Nikon are just as bad.