(This is a technical post about some of the "gotchas" when coding for .NET on 64- and 32-bit architectures.)
The short story:
The TeamFoundation client assemblies are x86-only assemblies. They don't work when called from an x64 .NET Application.
Even though they're in the GAC, you'll get a FileNotFoundException if the CLR tries to load them.
I already knew this, but it took me most of the day to realise that was my problem.
The long story:
Microsoft's .NET CLR 2.0 supports three different processor architectures: x86, x64 and IA-64. This means that there are three different CLR environments. x64 machines can host the x86 CLR alongside the native 64-bit CLR.
Although the CLR executes architecture-agnostic Common Intermediate Language (aka MSIL) code, any assembly can be marked as only suitable for one of the particular architectures.This is what happens when you choose a "Platform" type for a Visual Studio project. Choosing 'Any CPU' means that the project Assemblies are marked as language-agnostic CIL code.
It all plays out like this:
||Can Be Hosted From
||Can Load These Assembly Types
||x86 or x64 Operating Systems
||x86, "Any CPU"
||x64 Operating Systems
||x64, "Any CPU"
||Itanium Operating Systems
||IA-64, "Any CPU"
||Can Run On
|"Any CPU" / MSIL
||x86 CLR Only
||x64 CLR Only
||IA-64 CLR Only
To find out if an assembly is x86-only, you can use the CorFlags.exe utility which ships with the .NET SDK. You can also use this tool to tweak the assembly type, although doing this will break strong named assemblies and generally cause chaos.
When loading a.NET-based process, the .NET Framework decides which version of the CLR to load based on the assembly type. Processes based on "Any CPU" assemblies will load in the native CLR for the host system.
This can lead to some funny situations. For example, the ASP.NET Development Server application is 32-bit only, so any web sites you run on it will run in the x86 CLR. On the other hand, on x64 IIS can run either 32- or 64-bit ASP.NET applications. This means you can move your ASP.NET application from the Development Server to IIS on the same machine, and all of a sudden you will get a BadImageFormatException when an assembly refuses to load any more.
Sometimes you get a FileNotFoundException instead. This is when you try to reference an Assembly which is in the GAC.
... and you think "That's odd, I thought that assembly was in the GAC." and you look in the GAC browser, and there it is:
... the key is the "Processor Architecture" column on the righthand side.
As of .NET Framework 2.0, the CLR actually has four different GACs - one for each architecture, and one for "Any CPU" MSIL Assemblies. You can see this quite literally if you disable the GAC Shell extension, and browse to the GAC directory.
Each version of the CLR can only load assemblies which exist in its own GAC, or in the architecture-agnostic MSIL GAC. If you try to load an assembly from a different GAC, you'll see the FileNotFoundException.