⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 typeresolutionservice.cs

📁 SharpDevelop2.0.0 c#开发免费工具
💻 CS
字号:
// <file>
//     <copyright see="prj:///doc/copyright.txt"/>
//     <license see="prj:///doc/license.txt"/>
//     <owner name="Daniel Grunwald" email="daniel@danielgrunwald.de"/>
//     <version>$Revision: 1420 $</version>
// </file>

using System;
using System.IO;
using System.Reflection;
using System.Collections;
using System.Collections.Generic;
using System.Drawing;
using System.ComponentModel;
using System.ComponentModel.Design;
using ICSharpCode.SharpDevelop.Project;
using ICSharpCode.SharpDevelop.Dom;
using ICSharpCode.Core;
using System.Diagnostics;
using Microsoft.Win32;

namespace ICSharpCode.FormsDesigner.Services
{
	public class TypeResolutionService : ITypeResolutionService
	{
		readonly static List<Assembly> designerAssemblies = new List<Assembly>();
		// hash of file content -> Assembly
		readonly static Dictionary<string, Assembly> assemblyDict = new Dictionary<string, Assembly>();
		
		/// <summary>
		/// List of assemblies used by the form designer. This static list is not an optimal solution,
		/// but better than using AppDomain.CurrentDomain.GetAssemblies(). See SD2-630.
		/// </summary>
		public static List<Assembly> DesignerAssemblies {
			get {
				return designerAssemblies;
			}
		}
		
		static TypeResolutionService()
		{
			ClearMixedAssembliesTemporaryFiles();
			DesignerAssemblies.Add(ProjectContentRegistry.MscorlibAssembly);
			DesignerAssemblies.Add(ProjectContentRegistry.SystemAssembly);
			DesignerAssemblies.Add(typeof(System.Drawing.Point).Assembly);
			DesignerAssemblies.Add(typeof(System.Windows.Forms.Design.AnchorEditor).Assembly);
		}
		
		[System.Runtime.InteropServices.DllImport("kernel32.dll")]
		private static extern bool MoveFileEx(string lpExistingFileName, string lpNewFileName, int dwFlags);
		const int MOVEFILE_DELAY_UNTIL_REBOOT = 0x00000004;
		
		static void MarkFileToDeleteOnReboot(string fileName)
		{
			MoveFileEx(fileName, null, MOVEFILE_DELAY_UNTIL_REBOOT);
		}

		static void ClearMixedAssembliesTemporaryFiles()
		{
			string[] files = Directory.GetFiles(Path.GetTempPath(), "*.sd_forms_designer_mixed_assembly.dll");
			foreach (string fileName in files) {
				try {
					File.Delete(fileName);
				} catch {}
			}
			/* We don't need to debug controls inside the forms designer
			files = Directory.GetFiles(Path.GetTempPath(), "*.pdb");
			foreach (string fileName in files) {
				try {
					File.Delete(fileName);
				} catch {}
			}*/
		}

		
		string formSourceFileName;
		IProjectContent callingProject;
		
		/// <summary>
		/// Gets the project content of the project that created this TypeResolutionService.
		/// Returns null when no calling project was specified.
		/// </summary>
		public IProjectContent CallingProject {
			get {
				if (formSourceFileName != null) {
					if (ProjectService.OpenSolution != null) {
						IProject p = ProjectService.OpenSolution.FindProjectContainingFile(formSourceFileName);
						if (p != null) {
							callingProject = ParserService.GetProjectContent(p);
						}
					}
					formSourceFileName = null;
				}
				return callingProject;
			}
		}
		
		public TypeResolutionService()
		{
		}
		
		public TypeResolutionService(string formSourceFileName)
		{
			this.formSourceFileName = formSourceFileName;
		}
		
		/// <summary>
		/// Loads the assembly represented by the project content. Returns null on failure.
		/// </summary>
		public static Assembly LoadAssembly(IProjectContent pc)
		{
			// load dependencies of current assembly
			foreach (IProjectContent rpc in pc.ReferencedContents) {
				if (rpc is ParseProjectContent) {
					LoadAssembly(rpc);
				} else if (rpc is ReflectionProjectContent) {
					if (!(rpc as ReflectionProjectContent).IsGacAssembly)
						LoadAssembly(rpc);
				}
			}
			
			if (pc.Project != null) {
				return LoadAssembly(pc.Project.OutputAssemblyFullPath);
			} else if (pc is ReflectionProjectContent) {
				if ((pc as ReflectionProjectContent).IsGacAssembly)
					return LoadAssembly(new AssemblyName((pc as ReflectionProjectContent).AssemblyFullName), false);
				else
					return LoadAssembly((pc as ReflectionProjectContent).AssemblyLocation);
			} else {
				return null;
			}
		}
		
		static string GetHash(string fileName)
		{
			return Path.GetFileName(fileName).ToLowerInvariant() + File.GetLastWriteTimeUtc(fileName).Ticks.ToString();
		}
		
		/// <summary>
		/// Loads the file in none-locking mode. Returns null on failure.
		/// </summary>
		public static Assembly LoadAssembly(string fileName)
		{
			if (!File.Exists(fileName))
				return null;
			
			// FIX for SD2-716, remove when designer gets its own AppDomain
			foreach (Assembly asm in AppDomain.CurrentDomain.GetAssemblies()) {
				if (string.Equals(asm.Location, fileName, StringComparison.InvariantCultureIgnoreCase)) {
					RegisterAssembly(asm);
					return asm;
				}
			}
			
			string hash = GetHash(fileName);
			lock (assemblyDict) {
				Assembly asm;
				if (assemblyDict.TryGetValue(hash, out asm))
					return asm;
				LoggingService.Debug("Loading assembly " + fileName + " (hash " + hash + ")");
				try {
					asm = Assembly.Load(File.ReadAllBytes(fileName));
				} catch (BadImageFormatException e) {
					if (e.Message.Contains("HRESULT: 0x8013141D")) {
						LoggingService.Debug("Get HRESULt 0x8013141D, loading netmodule");
						//netmodule
						string tempPath = Path.GetTempFileName();
						File.Delete(tempPath);
						tempPath += ".sd_forms_designer_netmodule_assembly.dll";
						
						try {
							//convert netmodule to assembly
							Process p = new Process();
							p.StartInfo.UseShellExecute = false;
							p.StartInfo.FileName = Path.GetDirectoryName(typeof(object).Module.FullyQualifiedName) + Path.DirectorySeparatorChar + "al.exe";
							p.StartInfo.Arguments = "\"" + fileName +"\" /out:\"" + tempPath + "\"";
							p.StartInfo.CreateNoWindow = true;
							p.Start();
							p.WaitForExit();
							
							if(p.ExitCode == 0 && File.Exists(tempPath)) {
								byte[] asm_data = File.ReadAllBytes(tempPath);
								asm = Assembly.Load(asm_data);
								asm.LoadModule(Path.GetFileName(fileName), File.ReadAllBytes(fileName));
							}
						} catch (Exception ex) {
							MessageService.ShowError(ex, "Error calling linker for netmodule");
						}
						try {
							File.Delete(tempPath);
						} catch {}
					} else {
						throw; // don't ignore other load errors
					}
				} catch (FileLoadException e) {
					if (e.Message.Contains("HRESULT: 0x80131402")) {
						LoggingService.Debug("Get HRESULt 0x80131402, loading mixed modes asm from disk");
						//this is C++/CLI Mixed assembly which can only be loaded from disk, not in-memory
						string tempPath = Path.GetTempFileName();
						File.Delete(tempPath);
						tempPath += ".sd_forms_designer_mixed_assembly.dll";
						File.Copy(fileName, tempPath);
						
						/* We don't need to debug controls inside the forms designer
						string pdbpath = Path.GetDirectoryName(fileName) + Path.DirectorySeparatorChar + Path.GetFileNameWithoutExtension(fileName) + ".pdb";
						if (File.Exists(pdbpath)) {
							string newpdbpath = Path.GetTempPath() + Path.DirectorySeparatorChar + Path.GetFileName(pdbpath);
							try {
								File.Copy(pdbpath, newpdbpath);
								MarkFileToDeleteOnReboot(newpdbpath);
							} catch {
							}
						}
						 */
						asm = Assembly.LoadFile(tempPath);
						MarkFileToDeleteOnReboot(tempPath);
					} else {
						throw; // don't ignore other load errors
					}
				}
				
				AddAssemblyResolver();
				try {
					asm.GetTypes(); // force loading references etc.
				} catch {
					// some assemblies cause strange exceptions in Reflection...
				} finally {
					RemoveAssemblyResolver();
				}

				lock (designerAssemblies) {
					if (!designerAssemblies.Contains(asm))
						designerAssemblies.Insert(0, asm);
				}
				assemblyDict[hash] = asm;
				return asm;
			}
		}
		
		public static void RegisterAssembly(Assembly asm)
		{
			string file = asm.Location;
			if (file.Length > 0) {
				lock (assemblyDict) {
					assemblyDict[GetHash(file)] = asm;
				}
			}
			lock (designerAssemblies) {
				if (!designerAssemblies.Contains(asm))
					designerAssemblies.Insert(0, asm);
			}
		}
		
		public Assembly GetAssembly(AssemblyName name)
		{
			return LoadAssembly(name, false);
		}
		
		public Assembly GetAssembly(AssemblyName name, bool throwOnError)
		{
			return LoadAssembly(name, throwOnError);
		}
		
		static Assembly LoadAssembly(AssemblyName name, bool throwOnError)
		{
			try {
				Assembly asm = Assembly.Load(name);
				RegisterAssembly(asm);
				return asm;
			} catch (System.IO.FileLoadException) {
				if (throwOnError)
					throw;
				return null;
			}
		}
		
		public string GetPathOfAssembly(AssemblyName name)
		{
			Assembly assembly = GetAssembly(name);
			if (assembly != null) {
				return assembly.Location;
			}
			return null;
		}
		
		public Type GetType(string name)
		{
			return GetType(name, false, false);
		}
		
		public Type GetType(string name, bool throwOnError)
		{
			return GetType(name, throwOnError, false);
		}
		
		public Type GetType(string name, bool throwOnError, bool ignoreCase)
		{
			if (name == null || name.Length == 0) {
				return null;
			}
			if (IgnoreType(name)) {
				return null;
			}
			#if DEBUG
			if (!name.StartsWith("System.")) {
				LoggingService.Debug("TypeResolutionService: Looking for " + name);
			}
			#endif
			try {
				
				Type type = Type.GetType(name, false, ignoreCase);
				
				if (type == null) {
					IProjectContent pc = this.CallingProject;
					if (pc != null) {
						IClass foundClass = pc.GetClass(name.Replace('+', '.'));
						if (foundClass != null) {
							Assembly assembly = LoadAssembly(foundClass.ProjectContent);
							if (assembly != null) {
								type = assembly.GetType(name, false, ignoreCase);
							}
						}
					}
				}
				
				// type lookup for typename, assembly, xyz style lookups
				if (type == null) {
					int idx = name.IndexOf(",");
					if (idx > 0) {
						string[] splitName = name.Split(',');
						string typeName     = splitName[0];
						string assemblyName = splitName[1].Substring(1);
						Assembly assembly = null;
						try {
							assembly = Assembly.Load(assemblyName);
						} catch (Exception e) {
							LoggingService.Error(e);
						}
						if (assembly != null) {
							lock (designerAssemblies) {
								if (!designerAssemblies.Contains(assembly))
									designerAssemblies.Add(assembly);
							}
							type = assembly.GetType(typeName, false, ignoreCase);
						} else {
							type = Type.GetType(typeName, false, ignoreCase);
						}
					}
				}

				if (type == null) {
					lock (designerAssemblies) {
						foreach (Assembly asm in DesignerAssemblies) {
							Type t = asm.GetType(name, false);
							if (t != null) {
								return t;
							}
						}
					}
				}
				
				if (throwOnError && type == null)
					throw new TypeLoadException(name + " not found by TypeResolutionService");
				
				return type;
			} catch (Exception e) {
				LoggingService.Error(e);
			}
			return null;
		}
		
		public void ReferenceAssembly(AssemblyName name)
		{
			ICSharpCode.Core.LoggingService.Warn("TODO: Add Assembly reference : " + name);
		}
		
		#region VSDesigner workarounds
		/// <summary>
		/// HACK - Ignore any requests for types from the Microsoft.VSDesigner
		/// assembly.  There are smart tag problems if data adapter
		/// designers are used from this assembly.
		/// </summary>
		bool IgnoreType(string name)
		{
			int idx = name.IndexOf(",");
			if (idx > 0) {
				string[] splitName = name.Split(',');
				string assemblyName = splitName[1].Substring(1);
				if (assemblyName == "Microsoft.VSDesigner") {
					return true;
				}
			}
			return false;
		}
		
		static string vsDesignerIdeDir;
		
		static void RegisterVSDesignerWorkaround()
		{
			if (vsDesignerIdeDir == null) {
				vsDesignerIdeDir = "";
				RegistryKey key = Registry.LocalMachine.OpenSubKey(@"SOFTWARE\Microsoft\VisualStudio\8.0\Setup\VS");
				if (key != null) {
					vsDesignerIdeDir = key.GetValue("VS7CommonDir") as string ?? "";
					if (vsDesignerIdeDir.Length > 0) {
						vsDesignerIdeDir = Path.Combine(vsDesignerIdeDir, "IDE");
						AppDomain.CurrentDomain.AssemblyResolve += delegate(object sender, ResolveEventArgs args) {
							string shortName = args.Name;
							if (shortName.IndexOf(',') >= 0) {
								shortName = shortName.Substring(0, shortName.IndexOf(','));
							}
							if (shortName.StartsWith("Microsoft.")
							    && File.Exists(Path.Combine(vsDesignerIdeDir, shortName + ".dll")))
							{
								return Assembly.LoadFrom(Path.Combine(vsDesignerIdeDir, shortName + ".dll"));
							}
							return null;
						};
					}
				}
			}
		}
		#endregion
		
		public static void AddAssemblyResolver()
		{
			RegisterVSDesignerWorkaround();
			AppDomain.CurrentDomain.AssemblyResolve += AssemblyResolveEventHandler;
		}
		
		public static void RemoveAssemblyResolver()
		{
			AppDomain.CurrentDomain.AssemblyResolve -= AssemblyResolveEventHandler;
		}
		
		static Assembly AssemblyResolveEventHandler(object sender, ResolveEventArgs args)
		{
			LoggingService.Debug("TypeResolutionService: AssemblyResolveEventHandler: " + args.Name);
			
			Assembly lastAssembly = null;
			
			foreach (Assembly asm in TypeResolutionService.DesignerAssemblies) {
				if (asm.FullName == args.Name) {
					return asm;
				}
			}
			
			foreach (Assembly asm in AppDomain.CurrentDomain.GetAssemblies()) {
				if (asm.FullName == args.Name) {
					lastAssembly = asm;
				}
			}
			if (lastAssembly != null) {
				TypeResolutionService.DesignerAssemblies.Add(lastAssembly);
				LoggingService.Info("ICSharpAssemblyResolver found..." + args.Name);
			}
			return lastAssembly;
		}
	}
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -