From 7d34f5b122b0d3ab5844638c5d12e3cddbb7e811 Mon Sep 17 00:00:00 2001 From: Daniel Grunwald Date: Wed, 10 Aug 2005 09:39:57 +0000 Subject: [PATCH] When loading referenced assemblies for code completion that have missing dependencies, try to find best available version. For example, when using a library compiled against .NET 1.0; but only .NET 2.0 is installed, redirect the ReflectionOnlyAssemblyResolve event to load the .NET 2.0 version of System.dll instead. git-svn-id: svn://svn.sharpdevelop.net/sharpdevelop/trunk@344 1ccf3a8d-04fe-1044-b7c0-cef0b8235c61 --- .../Src/Project/Items/ReferenceProjectItem.cs | 48 ++--------- .../Services/ParserService/ParserService.cs | 2 + .../ParserService/ProjectContentRegistry.cs | 84 +++++++++++++++++-- 3 files changed, 87 insertions(+), 47 deletions(-) diff --git a/src/Main/Base/Project/Src/Project/Items/ReferenceProjectItem.cs b/src/Main/Base/Project/Src/Project/Items/ReferenceProjectItem.cs index 6748dcf063..b57f153697 100644 --- a/src/Main/Base/Project/Src/Project/Items/ReferenceProjectItem.cs +++ b/src/Main/Base/Project/Src/Project/Items/ReferenceProjectItem.cs @@ -65,19 +65,22 @@ namespace ICSharpCode.SharpDevelop.Project try { string hintPath = HintPath; - if (hintPath != null && hintPath.Length > 0) - { + if (hintPath != null && hintPath.Length > 0) { return Path.Combine(Project.Directory, hintPath); } string name = Path.Combine(Project.Directory, Include); - if (File.Exists(name)) - { + if (File.Exists(name)) { return name; } + if (File.Exists(name + ".dll")) { + return name + ".dll"; + } + if (File.Exists(name + ".exe")) { + return name + ".exe"; + } } catch (Exception) { } - - return GetPathToGACAssembly(Include); + return Include; } set { // Set by file name is unsupported by references. (otherwise GAC references might have strange renaming effects ...) @@ -99,38 +102,5 @@ namespace ICSharpCode.SharpDevelop.Project Include, Properties); } - - static string GetPathToGACAssembly(string referenceName) - { - string[] info = referenceName.Split(','); - - if (info.Length < 4) { - try { - Assembly refAssembly = ProjectContentRegistry.LoadGACAssembly(referenceName, true); - - // if it failed, then return just the short name - if (refAssembly == null) { - return info[0]; - } - - // split up the peices again to find the assembly file path - info = refAssembly.FullName.Split(','); - } catch (Exception) { - return referenceName; - } - } - - string aName = info[0]; - string aVersion = info[1].Substring(info[1].LastIndexOf('=') + 1); - string aPublicKey = info[3].Substring(info[3].LastIndexOf('=') + 1); - - return FileUtility.Combine(System.Environment.GetFolderPath(Environment.SpecialFolder.System), - "..", - "assembly", - "GAC", - aName, - aVersion + "__" + aPublicKey, - aName + ".dll"); - } } } diff --git a/src/Main/Base/Project/Src/Services/ParserService/ParserService.cs b/src/Main/Base/Project/Src/Services/ParserService/ParserService.cs index 69a766265b..b4b6b87149 100644 --- a/src/Main/Base/Project/Src/Services/ParserService/ParserService.cs +++ b/src/Main/Base/Project/Src/Services/ParserService/ParserService.cs @@ -109,8 +109,10 @@ namespace ICSharpCode.Core { try { abortLoadSolutionProjectsThread = false; + LoggingService.Info("Start LoadSolutionProjects thread"); LoadSolutionProjectsInternal(); } finally { + LoggingService.Info("LoadSolutionProjects thread ended"); loadSolutionProjectsThread = null; } } diff --git a/src/Main/Base/Project/Src/Services/ParserService/ProjectContentRegistry.cs b/src/Main/Base/Project/Src/Services/ParserService/ProjectContentRegistry.cs index 8543ada423..473cc2cce8 100644 --- a/src/Main/Base/Project/Src/Services/ParserService/ProjectContentRegistry.cs +++ b/src/Main/Base/Project/Src/Services/ParserService/ProjectContentRegistry.cs @@ -19,6 +19,7 @@ using ICSharpCode.Core; using ICSharpCode.SharpDevelop.Project; using ICSharpCode.SharpDevelop.Gui; using ICSharpCode.SharpDevelop.Dom; +using MSjogren.GacTool.FusionNative; namespace ICSharpCode.Core { @@ -182,12 +183,9 @@ namespace ICSharpCode.Core static Assembly AssemblyResolve(object sender, ResolveEventArgs e) { - string shortName = e.Name; - LoggingService.Debug("ProjectContentRegistry.AssemblyResolve" + e.Name); - int pos = shortName.IndexOf(','); - if (pos > 0) - shortName = shortName.Substring(0, pos); - string path = Path.Combine(lookupDirectory, shortName); + AssemblyName name = new AssemblyName(e.Name); + LoggingService.Debug("ProjectContentRegistry.AssemblyResolve " + e.Name); + string path = Path.Combine(lookupDirectory, name.Name); if (File.Exists(path + ".dll")) { LoggingService.Debug("AssemblyResolve ReflectionOnlyLoadFrom .dll file"); return Assembly.ReflectionOnlyLoadFrom(path + ".dll"); @@ -203,10 +201,80 @@ namespace ICSharpCode.Core try { LoggingService.Debug("AssemblyResolve trying ReflectionOnlyLoad"); return Assembly.ReflectionOnlyLoad(e.Name); - } catch (FileNotFoundException ex) { - LoggingService.Warn("AssemblyResolve failed: " + ex.Message); + } catch (FileNotFoundException) { + LoggingService.Warn("AssemblyResolve: ReflectionOnlyLoad failed for " + e.Name); + // We can't get the assembly we want. + // But propably we can get a similar version of it. + AssemblyName fixedName = FindBestMatchingAssemblyName(e.Name); + LoggingService.Info("AssemblyResolve: FixedName: " + fixedName); + return Assembly.ReflectionOnlyLoad(fixedName.FullName); + } + } + + 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 names = new List(); + + 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); } public static Assembly LoadGACAssembly(string partialName, bool reflectionOnly)