From e5a67ebcd77fe75102814168da051d02a990e610 Mon Sep 17 00:00:00 2001 From: Andreia Gaita Date: Thu, 28 Apr 2016 19:54:20 +0200 Subject: [PATCH 1/2] Make sure our assembly resolver always runs Fixes #267 For some reason, the xaml loader fails miserably when trying to resolve where to load our DLLs from if they're not yet in the process. The directories it's scanning don't include the extension installation path, so it can't find any assemblies that are referenced directly from xaml (using types from other assemblies in code works fine, using them in xaml doesn't). We have an assembly resolver code path as part of our ResourceDictionary implementation (SharedDictionaryManager), so every xaml user control needs to have at least one include that uses SharedDictionaryManager in order to trigger the assembly resolver hook up and ensure that libraries are found. --- .../GitHub.VisualStudio.csproj | 4 ++ .../UI/Settings/OptionsControl.xaml | 58 ++----------------- .../UI/Settings/OptionsStyles.xaml | 58 +++++++++++++++++++ 3 files changed, 68 insertions(+), 52 deletions(-) create mode 100644 src/GitHub.VisualStudio/UI/Settings/OptionsStyles.xaml diff --git a/src/GitHub.VisualStudio/GitHub.VisualStudio.csproj b/src/GitHub.VisualStudio/GitHub.VisualStudio.csproj index 0d120be9f9..6606efe666 100644 --- a/src/GitHub.VisualStudio/GitHub.VisualStudio.csproj +++ b/src/GitHub.VisualStudio/GitHub.VisualStudio.csproj @@ -375,6 +375,10 @@ MSBuild:Compile GitHub.VisualStudio.UI + + Designer + MSBuild:Compile + Designer MSBuild:Compile diff --git a/src/GitHub.VisualStudio/UI/Settings/OptionsControl.xaml b/src/GitHub.VisualStudio/UI/Settings/OptionsControl.xaml index c2246cab0e..b6d10c5dbd 100644 --- a/src/GitHub.VisualStudio/UI/Settings/OptionsControl.xaml +++ b/src/GitHub.VisualStudio/UI/Settings/OptionsControl.xaml @@ -5,61 +5,15 @@ xmlns:local="clr-namespace:GitHub.VisualStudio.UI" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:prop="clr-namespace:GitHub.VisualStudio.UI;assembly=GitHub.VisualStudio.UI" + xmlns:cache="clr-namespace:GitHub.VisualStudio.Helpers" d:DesignHeight="200" mc:Ignorable="d"> - - + + + + + + + + + \ No newline at end of file From 7a88701d6607fe91852a3fe92c8632034122b6c4 Mon Sep 17 00:00:00 2001 From: Andreia Gaita Date: Thu, 28 Apr 2016 20:50:52 +0200 Subject: [PATCH 2/2] Put the assembly resolver in the package class Instead of relying on the xaml controls to include the class that hooks up the resolver, just hook it up on package initialization so it always runs. Also, remove useless base package class, it's not really doing anything useful. --- src/GitHub.VisualStudio/Base/PackageBase.cs | 25 ------ .../GitHub.VisualStudio.csproj | 5 -- src/GitHub.VisualStudio/GitHubPackage.cs | 83 ++++++++++++++----- .../UI/Settings/OptionsControl.xaml | 58 +++++++++++-- .../UI/Settings/OptionsStyles.xaml | 58 ------------- src/common/SharedDictionaryManager.cs | 54 ------------ 6 files changed, 114 insertions(+), 169 deletions(-) delete mode 100644 src/GitHub.VisualStudio/Base/PackageBase.cs delete mode 100644 src/GitHub.VisualStudio/UI/Settings/OptionsStyles.xaml diff --git a/src/GitHub.VisualStudio/Base/PackageBase.cs b/src/GitHub.VisualStudio/Base/PackageBase.cs deleted file mode 100644 index 04015a5a02..0000000000 --- a/src/GitHub.VisualStudio/Base/PackageBase.cs +++ /dev/null @@ -1,25 +0,0 @@ -using System; -using Microsoft.VisualStudio.Shell; - -namespace GitHub.VisualStudio.Base -{ - public abstract class PackageBase : Package - { - IServiceProvider serviceProvider; - protected IServiceProvider ServiceProvider - { - get { return serviceProvider; } - set { serviceProvider = value; } - } - - protected PackageBase() - { - ServiceProvider = this; - } - - protected PackageBase(IServiceProvider serviceProvider) - { - ServiceProvider = serviceProvider; - } - } -} diff --git a/src/GitHub.VisualStudio/GitHub.VisualStudio.csproj b/src/GitHub.VisualStudio/GitHub.VisualStudio.csproj index 6606efe666..bf60dd8ca7 100644 --- a/src/GitHub.VisualStudio/GitHub.VisualStudio.csproj +++ b/src/GitHub.VisualStudio/GitHub.VisualStudio.csproj @@ -214,7 +214,6 @@ - @@ -375,10 +374,6 @@ MSBuild:Compile GitHub.VisualStudio.UI - - Designer - MSBuild:Compile - Designer MSBuild:Compile diff --git a/src/GitHub.VisualStudio/GitHubPackage.cs b/src/GitHub.VisualStudio/GitHubPackage.cs index c991e15858..8584579220 100644 --- a/src/GitHub.VisualStudio/GitHubPackage.cs +++ b/src/GitHub.VisualStudio/GitHubPackage.cs @@ -1,6 +1,8 @@ using System; using System.ComponentModel.Composition; using System.Globalization; +using System.IO; +using System.Reflection; using System.Runtime.InteropServices; using GitHub.Extensions; using GitHub.Models; @@ -12,54 +14,94 @@ using Microsoft.VisualStudio.Shell; using Microsoft.VisualStudio.Shell.Interop; using Octokit; +using System.Linq; namespace GitHub.VisualStudio { - /// - /// This is the class that implements the package exposed by this assembly. - /// - /// The minimum requirement for a class to be considered a valid package for Visual Studio - /// is to implement the IVsPackage interface and register itself with the shell. - /// This package uses the helper classes defined inside the Managed Package Framework (MPF) - /// to do it: it derives from the Package class that provides the implementation of the - /// IVsPackage interface and uses the registration attributes defined in the framework to - /// register itself and its components with the shell. - /// - // This attribute tells the PkgDef creation utility (CreatePkgDef.exe) that this class is - // a package. [PackageRegistration(UseManagedResourcesOnly = true)] - // This attribute is used to register the information needed to show this package - // in the Help/About dialog of Visual Studio. [InstalledProductRegistration("#110", "#112", "1.0", IconResourceID = 400)] [Guid(GuidList.guidGitHubPkgString)] //[ProvideBindingPath] [ProvideMenuResource("Menus.ctmenu", 1)] //[ProvideAutoLoad(UIContextGuids.NoSolution)] + // this is the Git service GUID, so we load whenever it loads [ProvideAutoLoad("11B8E6D7-C08B-4385-B321-321078CDD1F8")] [ProvideToolWindow(typeof(GitHubPane), Orientation = ToolWindowOrientation.Right, Style = VsDockStyle.Tabbed, Window = EnvDTE.Constants.vsWindowKindSolutionExplorer)] [ProvideOptionPage(typeof(OptionsPage), "GitHub for Visual Studio", "General", 0, 0, supportsAutomation: true)] - public class GitHubPackage : PackageBase + public class GitHubPackage : Package { + // list of assemblies to be loaded from the extension installation path + static readonly string[] ourAssemblies = + { + "GitHub.Api", + "GitHub.App", + "GitHub.CredentialManagement", + "GitHub.Exports", + "GitHub.Exports.Reactive", + "GitHub.Extensions", + "GitHub.Extensions.Reactive", + "GitHub.UI", + "GitHub.UI.Reactive", + "GitHub.VisualStudio", + "GitHub.TeamFoundation", + "GitHub.TeamFoundation.14", + "GitHub.TeamFoundation.15", + "GitHub.VisualStudio.UI", + "System.Windows.Interactivity" + }; + + readonly IServiceProvider serviceProvider; + public GitHubPackage() { + serviceProvider = this; } public GitHubPackage(IServiceProvider serviceProvider) - : base(serviceProvider) { + this.serviceProvider = serviceProvider; } - protected override void Initialize() { + AppDomain.CurrentDomain.AssemblyResolve += LoadAssemblyFromRunDir; + base.Initialize(); - var menus = ServiceProvider.GetExportedValue(); + var menus = serviceProvider.GetExportedValue(); foreach (var menu in menus.Menus) - ServiceProvider.AddTopLevelMenuItem(menu.Guid, menu.CmdId, (s, e) => menu.Activate()); + serviceProvider.AddTopLevelMenuItem(menu.Guid, menu.CmdId, (s, e) => menu.Activate()); foreach (var menu in menus.DynamicMenus) - ServiceProvider.AddDynamicMenuItem(menu.Guid, menu.CmdId, menu.CanShow, menu.Activate); + serviceProvider.AddDynamicMenuItem(menu.Guid, menu.CmdId, menu.CanShow, menu.Activate); + } + + [System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Reliability", "CA2001:AvoidCallingProblematicMethods")] + static Assembly LoadAssemblyFromRunDir(object sender, ResolveEventArgs e) + { + try + { + var name = new AssemblyName(e.Name); + if (!ourAssemblies.Contains(name.Name)) + return null; + var path = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location); + var filename = Path.Combine(path, name.Name + ".dll"); + if (!File.Exists(filename)) + return null; + return Assembly.LoadFrom(filename); + } + catch (Exception ex) + { + var log = string.Format(CultureInfo.CurrentCulture, + "Error occurred loading {0} from {1}.{2}{3}{4}", + e.Name, + Assembly.GetExecutingAssembly().Location, + Environment.NewLine, + ex, + Environment.NewLine); + VsOutputLogger.Write(log); + } + return null; } } @@ -70,7 +112,6 @@ public class GHClient : GitHubClient public GHClient(IProgram program) : base(program.ProductHeader) { - } } } diff --git a/src/GitHub.VisualStudio/UI/Settings/OptionsControl.xaml b/src/GitHub.VisualStudio/UI/Settings/OptionsControl.xaml index b6d10c5dbd..c2246cab0e 100644 --- a/src/GitHub.VisualStudio/UI/Settings/OptionsControl.xaml +++ b/src/GitHub.VisualStudio/UI/Settings/OptionsControl.xaml @@ -5,15 +5,61 @@ xmlns:local="clr-namespace:GitHub.VisualStudio.UI" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:prop="clr-namespace:GitHub.VisualStudio.UI;assembly=GitHub.VisualStudio.UI" - xmlns:cache="clr-namespace:GitHub.VisualStudio.Helpers" d:DesignHeight="200" mc:Ignorable="d"> - - - - - + + - - - - \ No newline at end of file diff --git a/src/common/SharedDictionaryManager.cs b/src/common/SharedDictionaryManager.cs index c224bd7033..b9adc74c8d 100644 --- a/src/common/SharedDictionaryManager.cs +++ b/src/common/SharedDictionaryManager.cs @@ -11,65 +11,11 @@ namespace GitHub.VisualStudio.Helpers { public class SharedDictionaryManager : ResourceDictionary { - static readonly string[] ourAssemblies = - { - "GitHub.Api", - "GitHub.App", - "GitHub.CredentialManagement", - "GitHub.Exports", - "GitHub.Exports.Reactive", - "GitHub.Extensions", - "GitHub.Extensions.Reactive", - "GitHub.UI", - "GitHub.UI.Reactive", - "GitHub.VisualStudio", - "GitHub.TeamFoundation", - "GitHub.TeamFoundation.14", - "GitHub.TeamFoundation.15", - "GitHub.VisualStudio.UI" - }; - - readonly static int VSVersion; - static SharedDictionaryManager() - { - AppDomain.CurrentDomain.AssemblyResolve += LoadAssemblyFromRunDir; - var asm = AppDomain.CurrentDomain.GetAssemblies().FirstOrDefault(x => x.FullName.StartsWith("Microsoft.TeamFoundation", StringComparison.Ordinal)); - VSVersion = asm?.GetName().Version.Major ?? 14; - } - public SharedDictionaryManager() { currentTheme = Colors.DetectTheme(); } - [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Reliability", "CA2001:AvoidCallingProblematicMethods")] - static Assembly LoadAssemblyFromRunDir(object sender, ResolveEventArgs e) - { - try - { - var name = new AssemblyName(e.Name); - if (!ourAssemblies.Contains(name.Name)) - return null; - // This assembly should only be loaded in the matching VS version - if (name.Name.StartsWith("GitHub.TeamFoundation", StringComparison.Ordinal)) - { - if (!String.Equals("GitHub.TeamFoundation." + VSVersion, name.Name, StringComparison.Ordinal)) - return null; - } - var path = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location); - var filename = Path.Combine(path, name.Name + ".dll"); - if (!File.Exists(filename)) - return null; - return Assembly.LoadFrom(filename); - } - catch (Exception ex) - { - var log = string.Format(CultureInfo.CurrentCulture, "Error occurred loading {0} from {1}.{2}{3}{4}", e.Name, Assembly.GetExecutingAssembly().Location, Environment.NewLine, ex, Environment.NewLine); - VsOutputLogger.Write(log); - } - return null; - } - #region ResourceDictionaryImplementation [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] string currentTheme;