This is another x64 issue where I was really surprised that it does exist. When you compile in VS2010/MsBuild a managed target for which the corresponding serialization assembly is generated you will find that all works until you try to compile for 64 bit. There you will get:
"SGEN : error : An attempt was made to load an assembly with an incorrect format: xxxx.dll."
Here is the 32 bit SGen is called for the 64 bit target which cannot load a 64 bit assembly. I have no idea why MS did not provide a SGen compiled as Any CPU but the Windows SDK does bring in a 32 and 64 bit version of SGen. After a little digging around I quickly found that I can manually set the SGenToolPath MsBuild property. I could have patched
directly but then I would have changed the checksum of the file and future .NET Framework patches would not be able to patch this file anymore. Since the VS 2010 project format builds completely upon MsBuild I can set the path also in my Studio project for each build mode correctly.
By the way it is not enough to simply set “Generate serialization assembly” to On to get an xxx.XmlSerializers assembly for all public types.
The SGen task of the .NET Framework does by default only create an serialization assembly if it does contain types derived from some web proxy classes used for Web Services. To create an xml serializer type for all public types of my assembly I needed therefore to set for all build modes
MsBuild does automatically add all direct assembly references to SGen as well to allow SGen to create the serialization code for types which have base classes in other assemblies. This service is good but it is not perfect. If you have a deeper inheritance tree you will need more than all direct references of your assembly. Since SGen is located in the Windows SDK there is no way to specify a probing path relative to my build output directory since .NET allows only directories below the executable location as additional probing paths. I decided to make life easy and simply copy SGen to my build output directory to cover all possible cases.
At first I do need the path to the right sgen.exe in the current build mode. For this I did define the property __SdkSgenTool. I do need two tries to resolve the right SGen since the SDK can be in Program Files (32 bit Windows) or Program Files (x86) (64 bit Windows). Then I do copy sgen.exe to the build output directory $(TargetDir).
The only missing thing is that I do need to set SGenToolPath to my build output directory. This was harder as expected since as a normal property it was overwritten by other MsBuild tasks. The solution that finally did work was to create the already existing property and set the value to its final value when no other tasks could interfere.
Below is the “code” to make Sgen work in 64 bit. You need to define the __SdkSgenTool variable in all build modes since the post build steps like copy are executed regardless of the build mode.
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x64'">
<__SdkSgenTool Condition="exists('C:\Program Files (x86)\Microsoft SDKs\Windows\v7.0A\Bin\NETFX 4.0 Tools\x64\sgen.exe')">C:\Program Files (x86)\Microsoft SDKs\Windows\v7.0A\Bin\NETFX 4.0 Tools\x64\sgen.exe</__SdkSgenTool>
<__SdkSgenTool Condition="exists('C:\Program Files\Microsoft SDKs\Windows\v7.0A\Bin\NETFX 4.0 Tools\x64\sgen.exe')">C:\Program Files\Microsoft SDKs\Windows\v7.0A\Bin\NETFX 4.0 Tools\x64\sgen.exe</__SdkSgenTool>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<Copy SourceFiles="$(__SdkSgenTool)" DestinationFiles="$(TargetDir)\sgen.exe" SkipUnchangedFiles="true" />
<Output TaskParameter="Value" PropertyName="SGenToolPath" />
I have heard that this issue will be fixed with VS2012 which is a good thing. MsBuild is very powerful but I do prefer a working build in all build modes without any surprises. The path to SGen is hard coded since I do not expect that somebody does install Visual Studio to another location as Program Files. The SDK directories below Microsoft SDKs\Windows\ are normal downloadable Windows SDKs if they contain only a version number. If there is an A at the end these SDKs are the ones which Visual Studio does bring with.