public void Boot(MiniInstallerBridge bridge) { Assembly installerAssembly = Assembly.LoadFrom(Path.Combine(bridge.ExtractedPath, "MiniInstaller.exe")); Type installerType = installerAssembly.GetType("MiniInstaller.Program"); // Set up any fields which we can set up by Everest. /* * FieldInfo f_AsmMonoMod = installerType.GetField("AsmMonoMod"); * if (f_AsmMonoMod != null) * f_AsmMonoMod.SetValue(null, typeof(MonoModder).Assembly); */ FieldInfo f_LineLogger = installerType.GetField("LineLogger"); if (f_LineLogger != null) { // f_LineLogger.SetValue(null, new Action<string>(_ => progress.LogLine(_)).CastDelegate(f_LineLogger.FieldType)); f_LineLogger.SetValue(null, new Action <string>(bridge.LogLine).CastDelegate(f_LineLogger.FieldType)); } // Let's just run the mod installer... from our mod... while we're running the mod... object exitObject = installerAssembly.EntryPoint.Invoke(null, new object[] { new string[] { } }); if (exitObject != null && exitObject is int && ((int)exitObject) != 0) { throw new Exception($"Return code != 0, but {exitObject}"); } }
public void Boot(MiniInstallerBridge bridge) { Assembly installerAssembly = Assembly.LoadFrom(Path.Combine(bridge.Root, "MiniInstaller.exe")); Type installerType = installerAssembly.GetType("MiniInstaller.Program"); // Fix MonoMod dying when running with a debugger attached because it's running without a console. Hook hookReadKey = new Hook( typeof(Console).GetMethod("ReadKey", BindingFlags.Public | BindingFlags.Static, null, new Type[] { }, null), new Func <ConsoleKeyInfo>(() => { return(new ConsoleKeyInfo('\n', ConsoleKey.Enter, false, false, false)); }) ); // Fix old versions of MiniInstaller loading HookGen without RuntimeDetour. bool loadedRuntimeDetour = false; Hook hookLazyLoadAssembly = new Hook( installerType.GetMethod("LazyLoadAssembly", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static, null, new Type[] { typeof(string) }, null), new Func <Func <string, Assembly>, string, Assembly>((orig, path) => { if (path.EndsWith("MonoMod.RuntimeDetour.dll")) { loadedRuntimeDetour = true; } else if (path.EndsWith("MonoMod.RuntimeDetour.HookGen.exe") && !loadedRuntimeDetour) { Console.WriteLine("HACKFIX: Loading MonoMod.RuntimeDetour.dll before MonoMod.RuntimeDetour.HookGen.exe"); orig(path.Substring(0, path.Length - 4 - 8) + ".dll"); } return(orig(path)); }) ); TextReader origReader = Console.In; using (TextWriter fileWriter = new MiniInstallerBridgeWriter(bridge)) using (LogWriter logWriter = new LogWriter { STDOUT = Console.Out, File = fileWriter }) using (TextReader fakeReader = new MiniInstallerFakeInReader()) { Console.SetOut(logWriter); Console.SetIn(fakeReader); object exitObject = installerAssembly.EntryPoint.Invoke(null, new object[] { new string[] { } }); if (exitObject != null && exitObject is int && ((int)exitObject) != 0) { throw new Exception($"Return code != 0, but {exitObject}"); } Console.SetOut(logWriter.STDOUT); logWriter.STDOUT = null; Console.SetIn(origReader); } hookReadKey.Undo(); hookLazyLoadAssembly.Undo(); }
public MiniInstallerBridgeWriter(MiniInstallerBridge bridge) { Bridge = bridge; }
public static IEnumerator Install(string root) { Environment.CurrentDirectory = root; yield return(StatusSilent("Starting MiniInstaller", false, "monomod", false)); using (MiniInstallerBridge bridge = new MiniInstallerBridge { Encoding = Console.Error.Encoding, Root = root }) { bridge.LogEvent = new ManualResetEvent(false); WaitHandle[] waitHandle = new WaitHandle[] { bridge.LogEvent }; Thread thread = new Thread(() => { AppDomain nest = null; try { AppDomainSetup nestInfo = new AppDomainSetup(); // nestInfo.ApplicationBase = Path.GetDirectoryName(root); nestInfo.ApplicationBase = Path.GetDirectoryName(Assembly.GetEntryAssembly().Location); nestInfo.LoaderOptimization = LoaderOptimization.SingleDomain; nest = AppDomain.CreateDomain( AppDomain.CurrentDomain.FriendlyName + " - MiniInstaller", AppDomain.CurrentDomain.Evidence, nestInfo, AppDomain.CurrentDomain.PermissionSet ); ((MiniInstallerProxy)nest.CreateInstanceAndUnwrap( typeof(MiniInstallerProxy).Assembly.FullName, typeof(MiniInstallerProxy).FullName )).Boot(bridge); AppDomain.Unload(nest); bridge.IsDone = true; bridge.WriteLine("MiniInstaller finished"); } catch (Exception e) { bridge.Exception = e; string msg = "MiniInstaller died a brutal death"; if (nest != null) { try { AppDomain.Unload(nest); } catch { msg = "MiniInstaller has become a zombie"; } } bridge.IsDone = true; bridge.WriteLine(msg); Console.Error.WriteLine(e); } }) { Name = "MiniInstaller" }; thread.Start(); string lastSent = null; while (!bridge.IsDone && thread.IsAlive) { WaitHandle.WaitAny(waitHandle, 1000); bridge.LogEvent.Reset(); if (lastSent != bridge.LastLogLine) { lastSent = bridge.LastLogLine; yield return(StatusSilent(lastSent, false, "monomod", false)); } } thread.Join(); if (bridge.Exception != null) { throw new Exception("MiniInstaller died a brutal death", bridge.Exception); } } }