ProcessorArchitecture and Assembly.FullName

If you haven’t noticed, assemblies in .Net framework 2.0 have a new name attribute ProcessorArchitecture. The attribute is exposed in AssemblyName class as a property ProcessorArchitecture.

 

If you pay a little
more attention, you will notice that the output of gacutil.exe is
different from what Assembly.FullName says.

 

C:\>gacutil -l system

Microsoft (R) .NET Global Assembly Cache Utility. Version 2.0.50908.00

Copyright (c) Microsoft Corporation. All rights reserved.

The Global Assembly Cache contains the following assemblies:

  system, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089, pro

cessorArchitecture=MSIL

Number of items = 1

 

C:\>fullname C:\Windows\Microsoft.Net\Framework\v2.0.50727\system.dll

Using Assembly.ReflectionOnlyLoadFrom:

FullName: System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089

Location: C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\system.dll

Codebase: file:///C:/WINDOWS/Microsoft.NET/Framework/v2.0.50727/system.dll

 

Specifically, Assembly.FullName does not give you the processorArchitecture!!!

 

Now here is the big question: WHY?

 

In fact, we have made
the change to include processorArchitecture in Assembly.FullName. When
we checked in the change, it caused a massive regression. We fixed all
the breaks. But because of the scale of the break it caused, we backed
out the change, and took it to DDCC (DDCC stands for Developer Division
Compatibility Council. It is a council to review every breaking change
in Visual Studio, including .Net framework and CLR). The proposal is
rejected by DDCC, fearing it will break many applications. We tried a
few other not-so-breaking ways to introduce processorArchitecture to
the display name, but none of them is satisfactory. So we have arrived
at the current state: Assembly.FullName gives you an assembly’s display
name without processorArchitecture.

 

The problems we have seen with the change to include processorArchitecture in Assembly.FullName are:

 

  1. Ref-Def matching. In
    v1.0/v1.1, essentially there is no difference between assembly
    reference and assembly definition. People use string comparison to do
    ref-def matching. This breaks down when processorArchitecture is added
    to the assembly definition (Assembly.FullName).

    We introduced the API AssemblyName.ReferenceMatchesDefinition, hoping people will move away from using string comparison APIs to compare assembly names.

  2. Related to 1).
    People use Assembly.FullName as a key to something, then use assembly
    reference to look up. This no longer works. 

     

  3. Cross platform
    Remoting/Serialization. Remoting/Serialization emits the assembly’s
    identity to binary blob so that the type can be constructed when
    de-serialized. When processorArchitecture is added to
    Assembly.FullName, you can no longer serialize a type from an x86
    assembly to AMD64 platform, since the original processorArchitecture
    (of “x86”) is carried over to AMD64 platform, the type can’t be
    instantiated.

    This actually reveals some inefficiency in
    Remoting/Serialization engine --- You can’t control how types are
    instantiated when cross platform.

I am sure people will find other problems if we had included processorArchitecture in Assembly.FullName.

 

But this leaves us a huge void --- There is no managed way to get the full display name of an assembly.

 

It is not a pleasant world. But we have to accept that.

 

Now if you really want to get the full display name of an assembly, you have to resort to unmanaged fusion API.

 

Assuming you use my Sample Managed GAC API Wrappers, you can use the following code snippet to achieve that:

 

                                               
String GetFullDisplayName(Assembly asm)

                                               
{

                                                               
AssemblyName asmName = asm.GetName();

                                                               
IAssemblyName fusionName = null;

                                                               
int hr = 0;

                                                               
// v1.0\v1.1 assembly, nothing to do here.

                                                               
if (asmName.ProcessorArchitecture == ProcessorArchitecture.None)

                                                               
{

                                                                               
return asm.FullName;

                                                               
}

                                                               
hr = Utils.CreateAssemblyNameObject(

                                                                               
out fusionName,

                                                                               
asm.FullName,

                                                                               
CreateAssemblyNameObjectFlags.CANOF_PARSE_DISPLAY_NAME,

                                                                               
IntPtr.Zero);

                                                               
if (hr >= 0)

                                                               
{

                                                                               
IntPtr pa = Marshal.AllocCoTaskMem(4);

                                                                               
Marshal.WriteInt32(pa, (int)asmName.ProcessorArchitecture));

                                                                               
hr = fusionName.SetProperty(ASM_NAME_ARCHITECTURE, pa, 4);

                                                                               
Marshal.FreeCoTaskMem(pa);

                                                               
}

                                                               
if (hr >=0 )

                                                               
{

                                                                               
StringBuilder sDisplayName = new StringBuilder(1024);

                                                                               
int iLen = 1024;

          

                                                                               
hr = fusionAsmName.GetDisplayName(sDisplayName, ref iLen, (int)AssemblyNameDisplayFlags.ALL);

                                                                               
if (hr >= 0 )

                                                                               
{

                                                                                               
return sDisplayName.ToString();

                                                                               
}

                                                               
}

                                                               
if (hr < 0)

                                                               
{

                                                                               
Marshal.ThrowExceptionForHR(hr);

                                                               
}

                                               
}

                               
}

 

ASM_NAME_ARCHITECTURE is defined in fusion.h, which is part of .Net framework 2.0 SDK.