Skip to content

Commit

Permalink
Merge branch 'hotfix/vs-updates' into develop
Browse files Browse the repository at this point in the history
  • Loading branch information
cwensley committed Oct 13, 2016
2 parents 194c67b + 481ffb2 commit 009e00c
Show file tree
Hide file tree
Showing 17 changed files with 157 additions and 35 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
using Eto.Wpf.Forms.Controls;
using sw = System.Windows;
using swc = System.Windows.Controls;
using System.Windows.Threading;

[assembly: PlatformInitializerAttribute(typeof(Eto.Addin.VisualStudio.Editor.PlatformInitializer))]

Expand Down Expand Up @@ -58,6 +59,11 @@ public Control FromContract(object contract)
view.Focusable = false; // otherwise editor loses focus when switching back to its tab.. may be a better way around this.
return new Control(new NativeControl(view));
}

public void Unload()
{
Dispatcher.CurrentDispatcher.InvokeShutdown();
}
}
}

Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<PackageManifest Version="2.0.0" xmlns="http://schemas.microsoft.com/developer/vsx-schema/2011" xmlns:d="http://schemas.microsoft.com/developer/vsx-schema-design/2011">
<Metadata>
<Identity Id="Eto.Addin.VisualStudio" Version="2.3.0.6" Language="en-US" Publisher="Curtis Wensley" />
<Identity Id="Eto.Addin.VisualStudio" Version="2.3.0.13" Language="en-US" Publisher="Curtis Wensley" />
<DisplayName>Eto.Forms Visual Studio Addin</DisplayName>
<Description xml:space="preserve">Eto.Forms Support for Visual Studio. Eto.Forms is a cross platform GUI framework for desktop and mobile applications in .NET that can target Wpf, WinForms, Direct2D, MonoMac, Xamarin.Mac, Gtk2, Gtk3, and iOS with a single codebase.</Description>
<MoreInfo>https://github.com/picoe/Eto</MoreInfo>
Expand Down
63 changes: 58 additions & 5 deletions Source/Eto.Designer/AppDomainDesignHost.cs
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
using Eto.Forms;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Security.Permissions;
using System.Text;
using System.Threading.Tasks;

Expand Down Expand Up @@ -32,22 +35,44 @@ public void Init(string platformType, string initializeAssembly, string mainAsse
{
if (Platform.Instance == null)
{
resolver = AssemblyResolver.Register(references.Union(new[] { mainAssembly, Path.GetDirectoryName(typeof(AppDomainProxy).Assembly.Location) }));
var refs = new[] { Path.GetDirectoryName(typeof(AppDomainProxy).Assembly.Location), mainAssembly };
resolver = AssemblyResolver.Register(refs.Union(references));

var plat = Activator.CreateInstance(Type.GetType(platformType)) as Platform;
Platform.Initialize(plat);
if (!string.IsNullOrEmpty(initializeAssembly))
{
plat.LoadAssembly(initializeAssembly);
}
new Application().Attach();
var app = new Application();
app.Attach();
app.Terminating += App_Terminating;

app.UnhandledException += App_UnhandledException;

AppDomain.CurrentDomain.DomainUnload += CurrentDomain_DomainUnload;
}

designPanel = new DesignPanel();
designPanel.MainAssembly = mainAssembly;
designPanel.References = references.ToList();
}

void App_UnhandledException(object sender, UnhandledExceptionEventArgs e)
{
// error!
}

void App_Terminating(object sender, CancelEventArgs e)
{
e.Cancel = true;
}

void CurrentDomain_DomainUnload(object sender, EventArgs e)
{
EtoAdapter.Unload();
}

Control container;
public object GetContainer()
{
Expand Down Expand Up @@ -75,6 +100,16 @@ public string GetCodeFile(string fileName)
{
return designPanel.GetCodeFile(fileName);
}

public void Dispose()
{
designPanel.Dispose();
}

public override object InitializeLifetimeService()
{
return null;
}
}

class AppDomainEventSink : MarshalByRefObject
Expand All @@ -90,8 +125,12 @@ public void Error(Exception ex)
{
Host.Error?.Invoke(ex);
}
}

public override object InitializeLifetimeService()
{
return null;
}
}

public class AppDomainDesignHost : IDesignHost, IDisposable
{
Expand Down Expand Up @@ -142,12 +181,14 @@ void Timer_Elapsed(object sender, EventArgs e)

IEnumerable<string> GetShadowCopyDirs()
{
yield return Path.GetDirectoryName(MainAssembly);
if (!string.IsNullOrEmpty(MainAssembly))
yield return Path.GetDirectoryName(MainAssembly);
if (References != null)
{
foreach (var r in References)
{
yield return Path.GetDirectoryName(r);
if (!string.IsNullOrEmpty(r))
yield return Path.GetDirectoryName(r);
}
}
}
Expand Down Expand Up @@ -175,11 +216,13 @@ bool SetupAppDomain(bool setBuilder)

ShadowCopyFiles = "true",
ShadowCopyDirectories = shadowCopyDirs,
CachePath = Path.Combine(Path.GetDirectoryName(MainAssembly), "Eto.Designer"),

LoaderOptimization = LoaderOptimization.MultiDomain,
//LoaderOptimization = LoaderOptimization.NotSpecified
};

proxy = null;
domain = AppDomain.CreateDomain("eto.designer." + domainCount++, null, setup);
try
{
Expand All @@ -191,6 +234,7 @@ bool SetupAppDomain(bool setBuilder)
throw new InvalidOperationException($"Could not create proxy for domain\nApplicationBase: {AppDomain.CurrentDomain.BaseDirectory}\nBaseDir: {baseDir}\nShadowCopyDirs: {shadowCopyDirs}");
}
proxy.Init(Platform.Instance.GetType().AssemblyQualifiedName, initializeAssembly, MainAssembly, references);
domain.DomainUnload += Domain_DomainUnload;

proxy.ControlCreated = eventSink.ControlCreated;
proxy.Error = eventSink.Error;
Expand All @@ -203,19 +247,26 @@ bool SetupAppDomain(bool setBuilder)
{
UnloadDomain(domain);
domain = null;
proxy = null;
throw new InvalidOperationException($"Could not set up proxy for domain: {ex.GetBaseException().Message}", ex);
}

if (watcher == null && !string.IsNullOrEmpty(MainAssembly))
{
watcher = new FileSystemWatcher(Path.GetDirectoryName(MainAssembly), "*.dll");
watcher.Changed += (sender, e) => Application.Instance.AsyncInvoke(() => timer.Start());
watcher.Created += (sender, e) => Application.Instance.AsyncInvoke(() => timer.Start());
watcher.EnableRaisingEvents = true;
}

return true;
}

static void Domain_DomainUnload(object sender, EventArgs e)
{
Debug.WriteLine("Unloaded");
}

public Action ContainerChanged { get; set; }

public Action ControlCreated { get; set; }
Expand Down Expand Up @@ -272,8 +323,10 @@ protected virtual void Dispose(bool disposing)
{
if (disposing)
{
proxy?.Dispose();
UnloadDomain(domain);
domain = null;
proxy = null;
}
}
}
Expand Down
2 changes: 1 addition & 1 deletion Source/Eto.Designer/AssemblyResolver.cs
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ Assembly Resolve(object sender, ResolveEventArgs args)
foreach (var path in Files)
{
var filePath = Path.GetFileNameWithoutExtension(path);
if (filePath == assemblyName && File.Exists(path))
if (string.Equals(filePath, assemblyName, StringComparison.OrdinalIgnoreCase) && File.Exists(path))
return Assembly.LoadFrom(path);
if (!Directory.Exists(path))
continue;
Expand Down
51 changes: 43 additions & 8 deletions Source/Eto.Designer/Builders/BaseCompiledInterfaceBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -52,21 +52,36 @@ public class CompileResult
public IEnumerable<string> Errors { get; set; }
}

protected abstract CompileResult Compile(string outputFile, string mainAssembly, IEnumerable<string> references, string code, out Assembly generatedAssembly);
protected abstract CompileResult Compile(string outputFile, IEnumerable<string> references, string code, out Assembly generatedAssembly);

public void Create(string text, string mainAssembly, IEnumerable<string> references, Action<Control> controlCreated, Action<Exception> error)
class BuildToken : IBuildToken
{
public bool IsCancelled { get; set; }
public void Cancel()
{
IsCancelled = true;
}
}
public IBuildToken Create(string text, string mainAssembly, IEnumerable<string> references, Action<Control> controlCreated, Action<Exception> error)
{
RemoveOutput();
var token = new BuildToken();

var refs = references?.ToList() ?? new List<string>();
// ensure we use the built-in version of Eto, not the one used by the project
if (!string.IsNullOrEmpty(mainAssembly))
refs.Insert(0, mainAssembly);
refs.RemoveAll(r => Path.GetFileName(r).ToLowerInvariant() == "eto.dll");
refs.Add(typeof(Control).Assembly.Location);

references = references?.ToList();
ThreadPool.QueueUserWorkItem(state =>
{
try
{
Assembly generatedAssembly;
//output = Path.Combine(Path.GetTempPath(), "EtoDesigner", Path.GetRandomFileName() + ".dll");

var result = Compile(null, mainAssembly, references, text, out generatedAssembly);
var result = Compile(null, refs, text, out generatedAssembly);
if (result.Success)
{
Application.Instance.Invoke(() =>
Expand All @@ -76,28 +91,36 @@ public void Create(string text, string mainAssembly, IEnumerable<string> referen
var type = FindControlType(generatedAssembly);
var control = InstantiateControl(type);

if (token.IsCancelled)
return;

if (control != null)
controlCreated(control);
else
error(new FormatException("Could not find control. Make sure you have a single class derived from Control."));
}
catch (Exception ex)
{
error(ex);
if (!token.IsCancelled)
error(ex);
}
});
}
else
{
var errorText = string.Join("\n", result.Errors);
Application.Instance.Invoke(() => error(new FormatException(string.Format("Compile error: {0}", errorText))));

if (!token.IsCancelled)
Application.Instance.Invoke(() => error(new FormatException(string.Format("Compile error: {0}", errorText))));
}
}
catch (Exception ex)
{
Application.Instance.Invoke(() => error(ex));
if (!token.IsCancelled)
Application.Instance.Invoke(() => error(ex));
}
});
return token;
}


Expand Down Expand Up @@ -137,11 +160,23 @@ protected string GetReferenceAssembliesFolder()
return referenceDir;
}

public static IEnumerable<Type> GetLoadableTypes(Assembly assembly)
{
try
{
return assembly.GetTypes();
}
catch (ReflectionTypeLoadException e)
{
return e.Types.Where(t => t != null);
}
}

public static Type FindControlType(Assembly assembly)
{
if (assembly == null)
return null;
return assembly.GetTypes().FirstOrDefault(t => typeof(Control).IsAssignableFrom(t));
return GetLoadableTypes(assembly).FirstOrDefault(t => typeof(Control).IsAssignableFrom(t));
}


Expand Down
4 changes: 1 addition & 3 deletions Source/Eto.Designer/Builders/CodeDomInterfaceBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ static void FixMonoPath()
}
}

protected override CompileResult Compile(string outputFile, string mainAssembly, IEnumerable<string> references, string code, out Assembly generatedAssembly)
protected override CompileResult Compile(string outputFile, IEnumerable<string> references, string code, out Assembly generatedAssembly)
{
var inMemory = string.IsNullOrEmpty(outputFile);
var parameters = new CompilerParameters
Expand All @@ -79,8 +79,6 @@ protected override CompileResult Compile(string outputFile, string mainAssembly,

SetParameters(parameters);

if (!string.IsNullOrEmpty(mainAssembly) && File.Exists(mainAssembly))
parameters.ReferencedAssemblies.Add(mainAssembly);
if (references != null)
{
foreach (var reference in references)
Expand Down
3 changes: 2 additions & 1 deletion Source/Eto.Designer/Builders/JsonInterfaceBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ namespace Eto.Designer.Builders
{
public class JsonInterfaceBuilder : IInterfaceBuilder
{
public void Create(string text, string mainAssembly, IEnumerable<string> references, Action<Forms.Control> controlCreated, Action<Exception> error)
public IBuildToken Create(string text, string mainAssembly, IEnumerable<string> references, Action<Forms.Control> controlCreated, Action<Exception> error)
{
try
{
Expand All @@ -27,6 +27,7 @@ public void Create(string text, string mainAssembly, IEnumerable<string> referen
{
error(ex);
}
return null;
}
}
}
5 changes: 4 additions & 1 deletion Source/Eto.Designer/Builders/RoslynCSharpInterfaceBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,10 @@ protected override Compilation CreateCompilation(SyntaxTree syntaxTree, string a
assemblyName,
syntaxTrees: new[] { syntaxTree },
references: references,
options: new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary));
options: new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary,
assemblyIdentityComparer: DesktopAssemblyIdentityComparer.Default
)
);
}
}
}
4 changes: 1 addition & 3 deletions Source/Eto.Designer/Builders/RoslynInterfaceBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -38,15 +38,13 @@ protected virtual IEnumerable<string> GetReferences()

protected abstract SyntaxTree ParseText(string code);

protected override CompileResult Compile(string outputFile, string mainAssembly, IEnumerable<string> references, string code, out Assembly generatedAssembly)
protected override CompileResult Compile(string outputFile, IEnumerable<string> references, string code, out Assembly generatedAssembly)
{
var syntaxTree = ParseText(code);

string assemblyName = Path.GetRandomFileName();
var refMetadata = GetReferences().Select(r => MetadataReference.CreateFromFile(r)).ToList();

if (!string.IsNullOrEmpty(mainAssembly) && File.Exists(mainAssembly))
refMetadata.Add(MetadataReference.CreateFromFile(mainAssembly));
if (references != null)
{
foreach (var reference in references)
Expand Down
3 changes: 2 additions & 1 deletion Source/Eto.Designer/Builders/XamlInterfaceBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ namespace Eto.Designer.Builders
{
public class XamlInterfaceBuilder : IInterfaceBuilder
{
public void Create(string text, string mainAssembly, IEnumerable<string> references, Action<Control> controlCreated, Action<Exception> error)
public IBuildToken Create(string text, string mainAssembly, IEnumerable<string> references, Action<Control> controlCreated, Action<Exception> error)
{
var oldDesignMode = XamlReader.DesignMode;
XamlReader.DesignMode = true;
Expand All @@ -34,6 +34,7 @@ public void Create(string text, string mainAssembly, IEnumerable<string> referen
{
XamlReader.DesignMode = oldDesignMode;
}
return null;
}
}
}
Loading

0 comments on commit 009e00c

Please sign in to comment.