// Copyright Microsoft Corporation.
// This source file is subject to the Microsoft Permissive License.
// See http://www.microsoft.com/resources/sharedsource/licensingbasics/sharedsourcelicenses.mspx.
// All other rights reserved.
#if !ROTOR
using System;
using System.Collections;
using System.Diagnostics;
using System.IO;
using System.Runtime.InteropServices;
using System.Text;
#if CCINamespace
namespace Microsoft.Cci{
#else
namespace System.Compiler
{
#endif
#if !FxCop
public
#endif
class GlobalAssemblyCache
{
private GlobalAssemblyCache() { }
private static readonly object Lock = new object();
private static bool FusionLoaded;
/// <param name="codeBaseUri">Uri pointing to the assembly</param>
public static bool Contains(Uri codeBaseUri)
{
if (codeBaseUri == null) { Debug.Fail("codeBaseUri == null"); return false; }
lock (GlobalAssemblyCache.Lock)
{
if (!GlobalAssemblyCache.FusionLoaded)
{
GlobalAssemblyCache.FusionLoaded = true;
System.Reflection.Assembly systemAssembly = typeof(object).Assembly;
//^ assume systemAssembly != null && systemAssembly.Location != null;
string dir = Path.GetDirectoryName(systemAssembly.Location);
//^ assume dir != null;
GlobalAssemblyCache.LoadLibrary(Path.Combine(dir, "fusion.dll"));
}
IAssemblyEnum assemblyEnum;
int rc = GlobalAssemblyCache.CreateAssemblyEnum(out assemblyEnum, null, null, ASM_CACHE.GAC, 0);
if (rc < 0 || assemblyEnum == null) return false;
IApplicationContext applicationContext;
IAssemblyName currentName;
while (assemblyEnum.GetNextAssembly(out applicationContext, out currentName, 0) == 0)
{
//^ assume currentName != null;
AssemblyName assemblyName = new AssemblyName(currentName);
string scheme = codeBaseUri.Scheme;
if (scheme != null && assemblyName.CodeBase.StartsWith(scheme))
{
try
{
Uri foundUri = new Uri(assemblyName.CodeBase);
if (codeBaseUri.Equals(foundUri)) return true;
#if !FxCop
}
catch (Exception)
{
#else
}finally{
#endif
}
}
}
return false;
}
}
/// <summary>
/// Returns the original location of the corresponding assembly if available, otherwise returns the location of the shadow copy.
/// If the corresponding assembly is not in the GAC, null is returned.
/// </summary>
public static string GetLocation(AssemblyReference assemblyReference)
{
if (assemblyReference == null) { Debug.Fail("assemblyReference == null"); return null; }
lock (GlobalAssemblyCache.Lock)
{
if (!GlobalAssemblyCache.FusionLoaded)
{
GlobalAssemblyCache.FusionLoaded = true;
System.Reflection.Assembly systemAssembly = typeof(object).Assembly;
//^ assume systemAssembly != null && systemAssembly.Location != null;
string dir = Path.GetDirectoryName(systemAssembly.Location);
//^ assume dir != null;
GlobalAssemblyCache.LoadLibrary(Path.Combine(dir, "fusion.dll"));
}
IAssemblyEnum assemblyEnum;
CreateAssemblyEnum(out assemblyEnum, null, null, ASM_CACHE.GAC, 0);
if (assemblyEnum == null) return null;
IApplicationContext applicationContext;
IAssemblyName currentName;
while (assemblyEnum.GetNextAssembly(out applicationContext, out currentName, 0) == 0)
{
//^ assume currentName != null;
AssemblyName aName = new AssemblyName(currentName);
if (assemblyReference.Matches(aName.Name, aName.Version, aName.Culture, aName.PublicKeyToken))
{
string codeBase = aName.CodeBase;
if (codeBase != null && codeBase.StartsWith("file:///"))
return codeBase.Substring(8);
return aName.GetLocation();
}
}
return null;
}
}
[DllImport("kernel32.dll", CharSet = CharSet.Ansi)]
private static extern IntPtr LoadLibrary(string lpFileName);
[DllImport("fusion.dll", CharSet = CharSet.Auto)]
private static extern int CreateAssemblyEnum(out IAssemblyEnum ppEnum, IApplicationContext pAppCtx, IAssemblyName pName, uint dwFlags, int pvReserved);
private class ASM_CACHE
{
private ASM_CACHE() { }
public const uint ZAP = 1;
public const uint GAC = 2;
public const uint DOWNLOAD = 4;
}
}
internal class AssemblyName
{
IAssemblyName/*!*/ assemblyName;
internal AssemblyName(IAssemblyName/*!*/ assemblyName)
{
this.assemblyName = assemblyName;
//^ base();
}
internal string/*!*/ Name
{
//set {this.WriteString(ASM_NAME.NAME, value);}
get { return this.ReadString(ASM_NAME.NAME); }
}
internal Version Version
{
//set{
// if (value == null) throw new ArgumentNullException();
// this.WriteUInt16(ASM_NAME.MAJOR_VERSION, (ushort)value.Major);
// this.WriteUInt16(ASM_NAME.MINOR_VERSION, (ushort)value.Minor);
// this.WriteUInt16(ASM_NAME.BUILD_NUMBER, (ushort)value.Build);
// this.WriteUInt16(ASM_NAME.REVISION_NUMBER, (ushort)value.Revision);
//}
get
{
int major = this.ReadUInt16(ASM_NAME.MAJOR_VERSION);
int minor = this.ReadUInt16(ASM_NAME.MINOR_VERSION);
int build = this.ReadUInt16(ASM_NAME.BUILD_NUMBER);
int revision = this.ReadUInt16(ASM_NAME.REVISION_NUMBER);
return new Version(major, minor, build, revision);
}
}
internal string/*!*/ Culture
{
//set {this.WriteString(ASM_NAME.CULTURE, value);}
get { return this.ReadString(ASM_NAME.CULTURE); }
}
internal byte[]/*!*/ PublicKeyToken
{
//set {this.WriteBytes(ASM_NAME.PUBLIC_KEY_TOKEN, value); }
get { return this.ReadBytes(ASM_NAME.PUBLIC_KEY_TOKEN); }
}
internal string StrongName
{
get
{
uint size = 0;
this.assemblyName.GetDisplayName(null, ref size, (uint)AssemblyNameDisplayFlags.ALL);
if (size == 0) return "";
StringBuilder strongName = new StringBuilder((int)size);
this.assemblyName.GetDisplayName(strongName, ref size, (uint)AssemblyNameDisplayFlags.ALL);
return strongName.ToString();
}
}
internal string/*!*/ CodeBase
{
//set {this.WriteString(ASM_NAME.CODEBASE_URL, value);}
get { return this.ReadString(ASM_NAME.CODEBASE_URL); }
}
public override string ToString()
{
return this.StrongName;
}
internal string GetLocation()
{
IAssemblyCache assemblyCache;
CreateAssemblyCache(out assemblyCache, 0);
if (assemblyCache == null) return null;
ASSEMBLY_INFO assemblyInfo = new ASSEMBLY_INFO();
assemblyInfo.cbAssemblyInfo = (uint)Marshal.SizeOf(typeof(ASSEMBLY_INFO));
assemblyCache.QueryAssemblyInfo(ASSEMBLYINFO_FLAG.VALIDATE | ASSEMBLYINFO_FLAG.GETSIZE, this.StrongName, ref assemblyInfo);
if (assemblyInfo.cbAssemblyInfo == 0) return null;
assemblyInfo.pszCurrentAssemblyPathBuf = new string(new char[assemblyInfo.cchBuf]);
assemblyCache.QueryAssemblyInfo(ASSEMBLYINFO_FLAG.VALIDATE | ASSEMBLYINFO_FLAG.GETSIZE, this.StrongName, ref assemblyInfo);
String value = assemblyInfo.pszCurrentAssemblyPathBuf;
return value;
}
private string/*!*/ ReadString(uint assemblyNameProperty)
{
uint size = 0;
this.assemblyName.GetProperty(assemblyNameProperty, IntPtr.Zero, ref size);
if (size == 0 || size > Int16.MaxValue) return String.Empty;
IntPtr ptr = Marshal.AllocHGlobal((int)size);
this.assemblyName.GetProperty(assemblyNameProperty, ptr, ref size);
String str = Marshal.PtrToStringUni(ptr);
//^ assume str != null;
Marshal.FreeHGlobal(ptr);
return str;
}
private ushort ReadUInt16(uint assemblyNameProperty)
{
uint size = 0;
this.assemblyName.GetProperty(assemblyNameProperty, IntPtr.Zero, ref size);
IntPtr ptr = Marshal.AllocHGlobal((int)size);
this.assemblyName.GetProperty(assemblyNameProperty, ptr, ref size);
ushort value = (ushort)Marshal.ReadInt16(ptr);
Marshal.FreeHGlobal(ptr);
return value;
}
private byte[]/*!*/ ReadBytes(uint assemblyNameProperty)
{
uint size = 0;
this.assemblyName.GetProperty(assemblyNameProperty, IntPtr.Zero, ref size);
IntPtr ptr = Marshal.AllocHGlobal((int)size);
this.assemblyName.GetProperty(assemblyNameProperty, ptr, ref size);
byte[] value = new byte[(int)size];
Marshal.Copy(ptr, value, 0, (int)size);
Marshal.FreeHGlobal(ptr);
return value;
}
[DllImport("fusion.dll", CharSet = CharSet.Auto)]
private static extern int CreateAssemblyCache(out IAssemblyCache ppAsmCache, uint dwReserved);
private class CREATE_ASM_NAME_OBJ_FLAGS
{
private CREATE_ASM_NAME_OBJ_FLAGS() { }
public const uint CANOF_PARSE_DISPLAY_NAME = 0x1;
public const uint CANOF_SET_DEFAULT_VALUES = 0x2;
}
private class ASM_NAME
{
private ASM_NAME() { }
public const uint PUBLIC_KEY = 0;
public const uint PUBLIC_KEY_TOKEN = 1;
public const uint HASH_VALUE = 2;
public const uint NAME = 3;
public const uint MAJOR_VERSION = 4;
public const uint MINOR_VERSION = 5;
public const uint BUILD_NUMBER = 6;
public const uint REVISION_NUMBER = 7;
public const uint CULTURE = 8;
public const uint PROCESSOR_ID_ARRAY = 9;
public const uint OSINFO_ARRAY = 10;
public const uint HASH_ALGID = 11;
public const uint ALIAS = 12;
public const uint CODEBASE_URL = 13;
public const uint CODEBASE_LASTMOD = 14;
public const uint NULL_PUBLIC_KEY = 15;
public const uint NULL_PUBLIC_KEY_TOKEN = 16;
public const uint CUSTOM = 17;
public const uint NULL_CUSTOM = 18;
public const uint MVID = 19;
public const uint _32_BIT_ONLY = 20;
}
[Flags]
internal enum AssemblyNameDisplayFlags
{
VERSION = 0x01,
CULTURE = 0x02,
PUBLIC_KEY_TOKEN = 0x04,
PROCESSORARCHITECTURE = 0x20,
RETARGETABLE = 0x80,
ALL = VERSION | CULTURE | PUBLIC_KEY_TOKEN | PROCESSORARCHITECTURE | RETARGETABLE
}
private class ASSEMBLYINFO_FLAG
{
private ASSEMBLYINFO_FLAG() { }
public const uint VALIDATE = 1;
public const uint GETSIZE = 2;
}
[StructLayout(LayoutKind.Sequential)]
private struct ASSEMBLY_INFO
{
public uint cbAssemblyInfo;
public uint dwAssemblyFlags;
public ulong uliAssemblySizeInKB;
[MarshalAs(UnmanagedType.LPWStr)]
public string pszCurrentAssemblyPathBuf;
public uint cchBuf;
}
[ComImport(), Guid("E707DCDE-D1CD-11D2-BAB9-00C04F8ECEAE"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
private interface IAssemblyCache
{
[PreserveSig()]
int UninstallAssembly(uint dwFlags, [MarshalAs(UnmanagedType.LPWStr)] string pszAssemblyName, IntPtr pvReserved, int pulDisposition);
[PreserveSig()]
int QueryAssemblyInfo(uint dwFlags, [MarshalAs(UnmanagedType.LPWStr)] string pszAssemblyName, ref ASSEMBLY_INFO pAsmInfo);
[PreserveSig()]
int CreateAssemblyCacheItem(uint dwFlags, IntPtr pvReserved, out object ppAsmItem, [MarshalAs(UnmanagedType.LPWStr)] string pszAssemblyName);
[PreserveSig()]
int CreateAssemblyScavenger(out object ppAsmScavenger);
[PreserveSig()]
int InstallAssembly(uint dwFlags, [MarshalAs(UnmanagedType.LPWStr)] string pszManifestFilePath, IntPtr pvReserved);
}
}
[ComImport(), Guid("CD193BC0-B4BC-11D2-9833-00C04FC31D2E"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
interface IAssemblyName
{
[PreserveSig()]
int SetProperty(uint PropertyId, IntPtr pvProperty, uint cbProperty);
[PreserveSig()]
int GetProperty(uint PropertyId, IntPtr pvProperty, ref uint pcbProperty);
[PreserveSig()]
int Finalize();
[PreserveSig()]
int GetDisplayName(StringBuilder szDisplayName, ref uint pccDisplayName, uint dwDisplayFlags);
[PreserveSig()]
int BindToObject(object refIID, object pAsmBindSink, IApplicationContext pApplicationContext, [MarshalAs(UnmanagedType.LPWStr)] string szCodeBase, long llFlags, int pvReserved, uint cbReserved, out int ppv);
[PreserveSig()]
int GetName(out uint lpcwBuffer, out int pwzName);
[PreserveSig()]
int GetVersion(out uint pdwVersionHi, out uint pdwVersionLow);
[PreserveSig()]
int IsEqual(IAssemblyName pName, uint dwCmpFlags);
[PreserveSig()]
int Clone(out IAssemblyName pName);
}
[ComImport(), Guid("7C23FF90-33AF-11D3-95DA-00A024A85B51"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
interface IApplicationContext
{
void SetContextNameObject(IAssemblyName pName);
void GetContextNameObject(out IAssemblyName ppName);
void Set([MarshalAs(UnmanagedType.LPWStr)] string szName, int pvValue, uint cbValue, uint dwFlags);
void Get([MarshalAs(UnmanagedType.LPWStr)] string szName, out int pvValue, ref uint pcbValue, uint dwFlags);
void GetDynamicDirectory(out int wzDynamicDir, ref uint pdwSize);
}
[ComImport(), Guid("21B8916C-F28E-11D2-A473-00C04F8EF448"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
interface IAssemblyEnum
{
[PreserveSig()]
int GetNextAssembly(out IApplicationContext ppAppCtx, out IAssemblyName ppName, uint dwFlags);
[PreserveSig()]
int Reset();
[PreserveSig()]
int Clone(out IAssemblyEnum ppEnum);
}
}
#else
//TODO: provide a way to query ROTOR GAC
#endif
|