From 45063aa6fa7cbdd3839a54390618f74ea2f92bed Mon Sep 17 00:00:00 2001
From: YoshiRulz <OSSYoshiRulz@gmail.com>
Date: Sat, 29 Aug 2020 00:57:07 +1000
Subject: [PATCH] Add helper for when calling .GetTypes() on EmuHawk assembly

---
 src/BizHawk.Client.EmuHawk/AVOut/IVideoWriter.cs |  4 +++-
 src/BizHawk.Client.EmuHawk/Api/ApiManager.cs     |  3 ++-
 src/BizHawk.Client.EmuHawk/MainForm.cs           |  2 +-
 .../tools/Lua/Win32LuaLibraries.cs               |  2 +-
 src/BizHawk.Client.EmuHawk/tools/ToolBox.cs      |  2 +-
 src/BizHawk.Client.EmuHawk/tools/ToolManager.cs  |  5 +++--
 .../tools/VirtualPads/VirtualpadsTool.cs         |  2 +-
 src/BizHawk.Common/Util.cs                       | 16 +++++++++++++++-
 8 files changed, 27 insertions(+), 9 deletions(-)

diff --git a/src/BizHawk.Client.EmuHawk/AVOut/IVideoWriter.cs b/src/BizHawk.Client.EmuHawk/AVOut/IVideoWriter.cs
index 72a076f7bb..473ede0e26 100644
--- a/src/BizHawk.Client.EmuHawk/AVOut/IVideoWriter.cs
+++ b/src/BizHawk.Client.EmuHawk/AVOut/IVideoWriter.cs
@@ -1,5 +1,7 @@
 using System;
 using System.Collections.Generic;
+
+using BizHawk.Common;
 using BizHawk.Emulation.Common;
 
 namespace BizHawk.Client.EmuHawk
@@ -143,7 +145,7 @@ namespace BizHawk.Client.EmuHawk
 
 		static VideoWriterInventory()
 		{
-			foreach (Type t in typeof(VideoWriterInventory).Assembly.GetTypes())
+			foreach (Type t in typeof(VideoWriterInventory).Assembly.GetTypesWithoutLoadErrors())
 			{
 				if (!t.IsInterface
 					&& typeof(IVideoWriter).IsAssignableFrom(t)
diff --git a/src/BizHawk.Client.EmuHawk/Api/ApiManager.cs b/src/BizHawk.Client.EmuHawk/Api/ApiManager.cs
index 8c562faae3..dca55bb3c4 100644
--- a/src/BizHawk.Client.EmuHawk/Api/ApiManager.cs
+++ b/src/BizHawk.Client.EmuHawk/Api/ApiManager.cs
@@ -6,6 +6,7 @@ using System.Linq;
 using System.Reflection;
 
 using BizHawk.Client.Common;
+using BizHawk.Common;
 using BizHawk.Emulation.Common;
 
 namespace BizHawk.Client.EmuHawk
@@ -15,7 +16,7 @@ namespace BizHawk.Client.EmuHawk
 		/// <remarks>keys are impl., values are interface</remarks>
 		private static readonly IReadOnlyDictionary<Type, Type> _apiTypes
 			= Assembly.GetAssembly(typeof(IEmuClientApi)).GetTypes()
-				.Concat(Assembly.GetAssembly(typeof(EmuClientApi)).GetTypes())
+				.Concat(Assembly.GetAssembly(typeof(EmuClientApi)).GetTypesWithoutLoadErrors())
 				.Where(t => /*t.IsClass &&*/t.IsSealed) // small optimisation; api impl. types are all sealed classes
 				.Select(t => (t, t.GetInterfaces().FirstOrDefault(t1 => typeof(IExternalApi).IsAssignableFrom(t1) && t1 != typeof(IExternalApi)))) // grab interface from impl. type...
 				.Where(tuple => tuple.Item2 != null) // ...if we couldn't determine what it's implementing, then it's not an api impl. type
diff --git a/src/BizHawk.Client.EmuHawk/MainForm.cs b/src/BizHawk.Client.EmuHawk/MainForm.cs
index 5d4eb9772f..d2fc8e4b65 100644
--- a/src/BizHawk.Client.EmuHawk/MainForm.cs
+++ b/src/BizHawk.Client.EmuHawk/MainForm.cs
@@ -1951,7 +1951,7 @@ namespace BizHawk.Client.EmuHawk
 
 		private static readonly IList<Type> _specializedTools = Assembly
 			.GetAssembly(typeof(MainForm))
-			.GetTypes()
+			.GetTypesWithoutLoadErrors()
 			.Where(t => typeof(IToolForm).IsAssignableFrom(t) && !t.IsAbstract)
 			.Where(t => t.GetCustomAttribute<SpecializedToolAttribute>() != null)
 			.ToList();
diff --git a/src/BizHawk.Client.EmuHawk/tools/Lua/Win32LuaLibraries.cs b/src/BizHawk.Client.EmuHawk/tools/Lua/Win32LuaLibraries.cs
index faca92024b..4a0955eb65 100644
--- a/src/BizHawk.Client.EmuHawk/tools/Lua/Win32LuaLibraries.cs
+++ b/src/BizHawk.Client.EmuHawk/tools/Lua/Win32LuaLibraries.cs
@@ -46,7 +46,7 @@ namespace BizHawk.Client.EmuHawk
 
 			// Register lua libraries
 			foreach (var lib in Assembly.Load("BizHawk.Client.Common").GetTypes()
-				.Concat(Assembly.GetAssembly(typeof(Win32LuaLibraries)).GetTypes())
+				.Concat(Assembly.GetAssembly(typeof(Win32LuaLibraries)).GetTypesWithoutLoadErrors())
 				.Where(t => typeof(LuaLibraryBase).IsAssignableFrom(t) && t.IsSealed && ServiceInjector.IsAvailable(serviceProvider, t)))
 			{
 				bool addLibrary = true;
diff --git a/src/BizHawk.Client.EmuHawk/tools/ToolBox.cs b/src/BizHawk.Client.EmuHawk/tools/ToolBox.cs
index c2b3a5f0d6..065411fb66 100644
--- a/src/BizHawk.Client.EmuHawk/tools/ToolBox.cs
+++ b/src/BizHawk.Client.EmuHawk/tools/ToolBox.cs
@@ -43,7 +43,7 @@ namespace BizHawk.Client.EmuHawk
 		{
 			ToolBoxStrip.Items.Clear();
 
-			var tools = Assembly.GetAssembly(GetType()).GetTypes()
+			var tools = Assembly.GetAssembly(GetType()).GetTypesWithoutLoadErrors()
 				.Where(t => typeof(IToolForm).IsAssignableFrom(t))
 				.Where(t => typeof(Form).IsAssignableFrom(t))
 				.Where(t => !typeof(ToolBox).IsAssignableFrom(t))
diff --git a/src/BizHawk.Client.EmuHawk/tools/ToolManager.cs b/src/BizHawk.Client.EmuHawk/tools/ToolManager.cs
index 7c9368d22b..16e6a65d8c 100644
--- a/src/BizHawk.Client.EmuHawk/tools/ToolManager.cs
+++ b/src/BizHawk.Client.EmuHawk/tools/ToolManager.cs
@@ -9,6 +9,7 @@ using System.ComponentModel;
 using System.Windows.Forms;
 
 using BizHawk.Client.Common;
+using BizHawk.Common;
 using BizHawk.Common.ReflectionExtensions;
 using BizHawk.Emulation.Common;
 using BizHawk.WinForms.Controls;
@@ -465,7 +466,7 @@ namespace BizHawk.Client.EmuHawk
 
 		public IEnumerable<Type> AvailableTools => Assembly
 			.GetAssembly(typeof(ToolManager))
-			.GetTypes()
+			.GetTypesWithoutLoadErrors()
 			.Where(t => typeof(IToolForm).IsAssignableFrom(t))
 			.Where(t => !t.IsInterface)
 			.Where(IsAvailable);
@@ -701,7 +702,7 @@ namespace BizHawk.Client.EmuHawk
 
 		private static readonly Lazy<List<string>> LazyAsmTypes = new Lazy<List<string>>(() =>
 			Assembly.GetAssembly(typeof(ToolManager)) // Confining the search to only EmuHawk, for now at least, we may want to broaden for external tools one day
-				.GetTypes()
+				.GetTypesWithoutLoadErrors()
 				.Select(t => t.AssemblyQualifiedName)
 				.ToList());
 
diff --git a/src/BizHawk.Client.EmuHawk/tools/VirtualPads/VirtualpadsTool.cs b/src/BizHawk.Client.EmuHawk/tools/VirtualPads/VirtualpadsTool.cs
index 9e9d9e7c91..f28d90d2f6 100644
--- a/src/BizHawk.Client.EmuHawk/tools/VirtualPads/VirtualpadsTool.cs
+++ b/src/BizHawk.Client.EmuHawk/tools/VirtualPads/VirtualpadsTool.cs
@@ -73,7 +73,7 @@ namespace BizHawk.Client.EmuHawk
 
 			var schemaType = Assembly
 				.GetExecutingAssembly()
-				.GetTypes()
+				.GetTypesWithoutLoadErrors()
 				.Where(t => typeof(IVirtualPadSchema)
 					.IsAssignableFrom(t) && t.GetCustomAttributes(false)
 					.OfType<SchemaAttribute>()
diff --git a/src/BizHawk.Common/Util.cs b/src/BizHawk.Common/Util.cs
index d4c3fa3967..1e9f51c812 100644
--- a/src/BizHawk.Common/Util.cs
+++ b/src/BizHawk.Common/Util.cs
@@ -4,6 +4,7 @@ using System.Diagnostics;
 using System.IO;
 using System.IO.Compression;
 using System.Linq;
+using System.Reflection;
 using System.Threading;
 
 namespace BizHawk.Common
@@ -79,7 +80,20 @@ namespace BizHawk.Common
 		/// <returns>all <see cref="Type">Types</see> with the name <paramref name="className"/></returns>
 		/// <remarks>adapted from https://stackoverflow.com/a/13727044/7467292</remarks>
 		public static IList<Type> GetTypeByName(string className) => AppDomain.CurrentDomain.GetAssemblies()
-			.SelectMany(asm => asm.GetTypes().Where(type => className.Equals(type.Name, StringComparison.InvariantCultureIgnoreCase))).ToList();
+			.SelectMany(asm => asm.GetTypesWithoutLoadErrors().Where(type => className.Equals(type.Name, StringComparison.InvariantCultureIgnoreCase))).ToList();
+
+		/// <remarks>TODO replace this with GetTypes (i.e. the try block) when VB.NET dep is properly removed</remarks>
+		public static IEnumerable<Type> GetTypesWithoutLoadErrors(this Assembly assembly)
+		{
+			try
+			{
+				return assembly.GetTypes();
+			}
+			catch (ReflectionTypeLoadException e)
+			{
+				return e.Types.Where(t => t != null);
+			}
+		}
 
 		/// <exception cref="ArgumentException"><paramref name="str"/> has an odd number of chars or contains a char not in <c>[0-9A-Fa-f]</c></exception>
 		public static byte[] HexStringToBytes(this string str)