浏览代码

Add a minimal assembly resolver before running main preloader code

ghorsington 5 年之前
父节点
当前提交
a8ceaa97ed
共有 1 个文件被更改,包括 45 次插入21 次删除
  1. 45 21
      BepInEx.Preloader/Entrypoint.cs

+ 45 - 21
BepInEx.Preloader/Entrypoint.cs

@@ -1,37 +1,20 @@
 using System;
+using System.IO;
 using System.Linq;
 using System.Reflection;
 
 namespace BepInEx.Preloader
 {
-	internal static class Entrypoint
+	internal static class PreloaderRunner
 	{
-		/// <summary>
-		///     The main entrypoint of BepInEx, called from Doorstop.
-		/// </summary>
-		/// <param name="args">
-		///     The arguments passed in from Doorstop. First argument is the path of the currently executing
-		///     process.
-		/// </param>
-		public static void Main(string[] args)
+		public static void PreloaderMain(string[] args)
 		{
 			Paths.SetExecutablePath(args[0]);
 			AppDomain.CurrentDomain.AssemblyResolve += LocalResolve;
-
 			Preloader.Run();
 		}
 
-		/// <summary>
-		///     A handler for <see cref="AppDomain.AssemblyResolve" /> to perform some special handling.
-		///     <para>
-		///         It attempts to check currently loaded assemblies (ignoring the version), and then checks the BepInEx/core path,
-		///         BepInEx/patchers path and the BepInEx folder, all in that order.
-		///     </para>
-		/// </summary>
-		/// <param name="sender"></param>
-		/// <param name="args"></param>
-		/// <returns></returns>
-		internal static Assembly LocalResolve(object sender, ResolveEventArgs args)
+		private static Assembly LocalResolve(object sender, ResolveEventArgs args)
 		{
 			var assemblyName = new AssemblyName(args.Name);
 
@@ -49,4 +32,45 @@ namespace BepInEx.Preloader
 			return null;
 		}
 	}
+
+	internal static class Entrypoint
+	{
+		private static string preloaderPath;
+
+		/// <summary>
+		///     The main entrypoint of BepInEx, called from Doorstop.
+		/// </summary>
+		/// <param name="args">
+		///     The arguments passed in from Doorstop. First argument is the path of the currently executing
+		///     process.
+		/// </param>
+		public static void Main(string[] args)
+		{
+			// Get the path of this DLL via Doorstop env var because Assembly.Location mangles non-ASCII characters on some versions of Mono for unknown reasons
+			preloaderPath = Path.GetDirectoryName(Path.GetFullPath(Environment.GetEnvironmentVariable("DOORSTOP_INVOKE_DLL_PATH")));
+
+			AppDomain.CurrentDomain.AssemblyResolve += ResolveCurrentDirectory;
+
+			// We have to use reflection and a separate startup class in order to not trigger premature assembly resolving
+			typeof(Entrypoint).Assembly.GetType($"BepInEx.Preloader.{nameof(PreloaderRunner)}")
+							  ?.GetMethod(nameof(PreloaderRunner.PreloaderMain))
+							  ?.Invoke(null, new object[] { args });
+
+			AppDomain.CurrentDomain.AssemblyResolve -= ResolveCurrentDirectory;
+		}
+
+		private static Assembly ResolveCurrentDirectory(object sender, ResolveEventArgs args)
+		{
+			var name = new AssemblyName(args.Name);
+
+			try
+			{
+				return Assembly.LoadFile(Path.Combine(preloaderPath, $"{name.Name}.dll"));
+			}
+			catch (Exception)
+			{
+				return null;
+			}
+		}
+	}
 }