You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
288 lines
9.5 KiB
288 lines
9.5 KiB
// <file> |
|
// <copyright see="prj:///doc/copyright.txt">2002-2005 AlphaSierraPapa</copyright> |
|
// <license see="prj:///doc/license.txt">GNU General Public License</license> |
|
// <owner name="Daniel Grunwald" email="daniel@danielgrunwald.de"/> |
|
// <version>$Revision$</version> |
|
// </file> |
|
|
|
using System; |
|
using System.IO; |
|
using System.Threading; |
|
using System.Collections; |
|
using System.Collections.Generic; |
|
using System.Diagnostics; |
|
using System.Reflection; |
|
using System.Xml; |
|
using System.Text; |
|
|
|
using ICSharpCode.Core; |
|
using ICSharpCode.SharpDevelop.Project; |
|
using ICSharpCode.SharpDevelop.Gui; |
|
using ICSharpCode.SharpDevelop.Dom; |
|
using MSjogren.GacTool.FusionNative; |
|
|
|
namespace ICSharpCode.Core |
|
{ |
|
public static class ProjectContentRegistry |
|
{ |
|
static Dictionary<string, IProjectContent> contents = new Dictionary<string, IProjectContent>(StringComparer.InvariantCultureIgnoreCase); |
|
static ReflectionProjectContent mscorlibContent; |
|
|
|
public static IProjectContent Mscorlib { |
|
get { |
|
if (mscorlibContent != null) return mscorlibContent; |
|
lock (contents) { |
|
if (contents.ContainsKey("mscorlib")) { |
|
mscorlibContent = (ReflectionProjectContent)contents["mscorlib"]; |
|
return contents["mscorlib"]; |
|
} |
|
int time = LoggingService.IsDebugEnabled ? Environment.TickCount : 0; |
|
LoggingService.Debug("Loading PC for mscorlib..."); |
|
mscorlibContent = DomPersistence.LoadProjectContentByAssemblyName(typeof(object).Assembly.FullName); |
|
if (mscorlibContent == null) { |
|
mscorlibContent = new ReflectionProjectContent(typeof(object).Assembly); |
|
if (time != 0) { |
|
LoggingService.Debug("Loaded mscorlib with reflection in " + (Environment.TickCount - time) + " ms"); |
|
} |
|
DomPersistence.SaveProjectContent(mscorlibContent); |
|
LoggingService.Debug("Saved mscorlib to cache"); |
|
} else { |
|
if (time != 0) { |
|
LoggingService.Debug("Loaded mscorlib from cache in " + (Environment.TickCount - time) + " ms"); |
|
} |
|
} |
|
contents["mscorlib"] = mscorlibContent; |
|
return mscorlibContent; |
|
} |
|
} |
|
} |
|
|
|
public static IProjectContent WinForms { |
|
get { |
|
lock (contents) { |
|
if (contents.ContainsKey("System.Windows.Forms")) { |
|
return contents["System.Windows.Forms"]; |
|
} |
|
} |
|
return GetProjectContentForReference(new ReferenceProjectItem(null, "System.Windows.Forms")); |
|
} |
|
} |
|
|
|
public static IProjectContent GetExistingProjectContent(AssemblyName assembly) |
|
{ |
|
lock (contents) { |
|
if (contents.ContainsKey(assembly.FullName)) { |
|
return contents[assembly.FullName]; |
|
} |
|
if (contents.ContainsKey(assembly.Name)) { |
|
return contents[assembly.Name]; |
|
} |
|
return null; |
|
} |
|
} |
|
|
|
public static IProjectContent GetProjectContentForReference(ReferenceProjectItem item) |
|
{ |
|
if (item is ProjectReferenceProjectItem) { |
|
if (((ProjectReferenceProjectItem)item).ReferencedProject == null) |
|
{ |
|
return null; |
|
} |
|
return ParserService.GetProjectContent(((ProjectReferenceProjectItem)item).ReferencedProject); |
|
} |
|
lock (contents) { |
|
string itemInclude = item.Include; |
|
string itemFileName = item.FileName; |
|
if (contents.ContainsKey(itemFileName)) { |
|
return contents[itemFileName]; |
|
} |
|
if (contents.ContainsKey(itemInclude)) { |
|
return contents[itemInclude]; |
|
} |
|
|
|
|
|
LoggingService.Debug("Loading PC for " + itemInclude); |
|
|
|
string shortName = itemInclude; |
|
int pos = shortName.IndexOf(','); |
|
if (pos > 0) |
|
shortName = shortName.Substring(0, pos); |
|
|
|
StatusBarService.ProgressMonitor.BeginTask("Loading " + shortName + "...", 100); |
|
#if DEBUG |
|
int time = Environment.TickCount; |
|
#endif |
|
try { |
|
Assembly assembly = GetDefaultAssembly(shortName); |
|
ReflectionProjectContent pc; |
|
if (assembly != null) { |
|
pc = DomPersistence.LoadProjectContentByAssemblyName(assembly.FullName); |
|
if (pc == null) { |
|
pc = new ReflectionProjectContent(assembly); |
|
DomPersistence.SaveProjectContent(pc); |
|
} |
|
} else { |
|
pc = LoadProjectContent(itemFileName, itemInclude); |
|
} |
|
if (pc != null) { |
|
contents[item.Include] = pc; |
|
contents[shortName] = pc; |
|
contents[pc.AssemblyFullName] = pc; |
|
} |
|
return pc; |
|
} finally { |
|
#if DEBUG |
|
LoggingService.DebugFormatted("Loaded {0} in {1}ms", itemInclude, Environment.TickCount - time); |
|
#endif |
|
StatusBarService.ProgressMonitor.Done(); |
|
} |
|
} |
|
} |
|
|
|
static ReflectionProjectContent LoadProjectContent(string filename, string include) |
|
{ |
|
ReflectionProjectContent pc = DomPersistence.LoadProjectContentByAssemblyName(filename); |
|
if (pc != null) { |
|
return pc; |
|
} |
|
pc = DomPersistence.LoadProjectContentByAssemblyName(include); |
|
if (pc != null) { |
|
return pc; |
|
} |
|
AppDomainSetup setup = new AppDomainSetup(); |
|
setup.DisallowCodeDownload = true; |
|
setup.ApplicationBase = AppDomain.CurrentDomain.BaseDirectory; |
|
AppDomain domain = AppDomain.CreateDomain("AssemblyLoadingDomain", AppDomain.CurrentDomain.Evidence, setup); |
|
string database; |
|
try { |
|
object o = domain.CreateInstanceAndUnwrap(typeof(ReflectionLoader).Assembly.FullName, typeof(ReflectionLoader).FullName); |
|
ReflectionLoader loader = (ReflectionLoader)o; |
|
database = loader.LoadAndCreateDatabase(filename, include); |
|
} catch (Exception e) { |
|
database = null; |
|
MessageService.ShowError(e); |
|
} finally { |
|
AppDomain.Unload(domain); |
|
} |
|
if (database == null) { |
|
LoggingService.Debug("AppDomain finished but returned null..."); |
|
return null; |
|
} else { |
|
LoggingService.Debug("AppDomain finished, loading cache..."); |
|
return DomPersistence.LoadProjectContent(database); |
|
} |
|
} |
|
|
|
static Assembly GetDefaultAssembly(string shortName) |
|
{ |
|
// These assemblies are already loaded by SharpDevelop, so we don't need to load |
|
// them in a separate AppDomain. |
|
switch (shortName) { |
|
case "System": // System != mscorlib !!! |
|
return typeof(Uri).Assembly; |
|
case "System.Data": |
|
return typeof(System.Data.DataException).Assembly; |
|
case "System.Design": |
|
return typeof(System.ComponentModel.Design.DesignSurface).Assembly; |
|
case "System.DirectoryServices": |
|
return typeof(System.DirectoryServices.AuthenticationTypes).Assembly; |
|
case "System.Drawing": |
|
return typeof(System.Drawing.Color).Assembly; |
|
case "System.Web.Services": |
|
return typeof(System.Web.Services.WebService).Assembly; |
|
case "System.Windows.Forms": |
|
return typeof(System.Windows.Forms.Control).Assembly; |
|
case "System.Xml": |
|
case "System.XML": |
|
return typeof(XmlReader).Assembly; |
|
case "Microsoft.Build.Engine": |
|
return typeof(Microsoft.Build.BuildEngine.BuildSettings).Assembly; |
|
case "Microsoft.Build.Framework": |
|
return typeof(Microsoft.Build.Framework.LoggerVerbosity).Assembly; |
|
default: |
|
return null; |
|
} |
|
} |
|
|
|
|
|
public static Assembly LoadGACAssembly(string partialName, bool reflectionOnly) |
|
{ |
|
if (reflectionOnly) { |
|
AssemblyName name = FindBestMatchingAssemblyName(partialName); |
|
if (name == null) |
|
return null; |
|
return Assembly.ReflectionOnlyLoad(name.FullName); |
|
} else { |
|
#pragma warning disable 618 |
|
return Assembly.LoadWithPartialName(partialName); |
|
#pragma warning restore 618 |
|
} |
|
} |
|
|
|
public static AssemblyName FindBestMatchingAssemblyName(string name) |
|
{ |
|
string[] info = name.Split(','); |
|
string version = (info.Length > 1) ? info[1].Substring(info[1].LastIndexOf('=') + 1) : null; |
|
string publicKey = (info.Length > 3) ? info[3].Substring(info[3].LastIndexOf('=') + 1) : null; |
|
|
|
IApplicationContext applicationContext = null; |
|
IAssemblyEnum assemblyEnum = null; |
|
IAssemblyName assemblyName; |
|
Fusion.CreateAssemblyNameObject(out assemblyName, info[0], 0, 0); |
|
Fusion.CreateAssemblyEnum(out assemblyEnum, null, assemblyName, 2, 0); |
|
List<string> names = new List<string>(); |
|
|
|
while (assemblyEnum.GetNextAssembly(out applicationContext, out assemblyName, 0) == 0) { |
|
uint nChars = 0; |
|
assemblyName.GetDisplayName(null, ref nChars, 0); |
|
|
|
StringBuilder sb = new StringBuilder((int)nChars); |
|
assemblyName.GetDisplayName(sb, ref nChars, 0); |
|
|
|
string fullName = sb.ToString(); |
|
if (publicKey != null) { |
|
info = fullName.Split(','); |
|
if (publicKey != info[3].Substring(info[3].LastIndexOf('=') + 1)) { |
|
// Assembly has wrong public key |
|
continue; |
|
} |
|
} |
|
names.Add(fullName); |
|
} |
|
if (names.Count == 0) |
|
return null; |
|
string best = null; |
|
Version bestVersion = null; |
|
Version currentVersion; |
|
if (version != null) { |
|
// use assembly with lowest version higher or equal to required version |
|
Version requiredVersion = new Version(version); |
|
for (int i = 0; i < names.Count; i++) { |
|
info = names[i].Split(','); |
|
currentVersion = new Version(info[1].Substring(info[1].LastIndexOf('=') + 1)); |
|
if (currentVersion.CompareTo(requiredVersion) < 0) |
|
continue; // version not good enough |
|
if (best == null || currentVersion.CompareTo(bestVersion) < 0) { |
|
bestVersion = currentVersion; |
|
best = names[i]; |
|
} |
|
} |
|
if (best != null) |
|
return new AssemblyName(best); |
|
} |
|
// use assembly with highest version |
|
best = names[0]; |
|
info = names[0].Split(','); |
|
bestVersion = new Version(info[1].Substring(info[1].LastIndexOf('=') + 1)); |
|
for (int i = 1; i < names.Count; i++) { |
|
info = names[i].Split(','); |
|
currentVersion = new Version(info[1].Substring(info[1].LastIndexOf('=') + 1)); |
|
if (currentVersion.CompareTo(bestVersion) > 0) { |
|
bestVersion = currentVersion; |
|
best = names[i]; |
|
} |
|
} |
|
return new AssemblyName(best); |
|
} |
|
} |
|
}
|
|
|