📄 typeresolutionservice.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 + -