|
@@ -1,7 +1,10 @@
|
|
|
using System;
|
|
|
using System.IO;
|
|
|
+using System.Linq;
|
|
|
+using System.Reflection;
|
|
|
using System.Text;
|
|
|
using BepInEx.ConsoleUtil;
|
|
|
+using HarmonyLib;
|
|
|
using Microsoft.Win32.SafeHandles;
|
|
|
using UnityInjector.ConsoleUtil;
|
|
|
|
|
@@ -9,11 +12,6 @@ namespace BepInEx
|
|
|
{
|
|
|
internal class WindowsConsoleDriver : IConsoleDriver
|
|
|
{
|
|
|
- // We need to save stdout and conout as SafeFileHandles because we can't pass it to FileStream (check comments in CreateConsole)
|
|
|
- // However, on some versions of Unity (e.g. 2018.4) using old mono causes crashes on game close if
|
|
|
- // the stdout and conout are not saved into a file handle (check #139)
|
|
|
- private SafeFileHandle _originalOutHandle, _consoleOutHandle;
|
|
|
-
|
|
|
public TextWriter StandardOut { get; private set; }
|
|
|
public TextWriter ConsoleOut { get; private set; }
|
|
|
|
|
@@ -27,18 +25,32 @@ namespace BepInEx
|
|
|
StandardOut = Console.Out;
|
|
|
}
|
|
|
|
|
|
+ // Apparently on some versions of Unity (e.g. 2018.4) using old mono causes crashes on game close if
|
|
|
+ // IntPtr overload is used for file streams (check #139).
|
|
|
+ // On the other hand, not all Unity games come with SafeFileHandle overload for FileStream
|
|
|
+ // As such, we're trying to use SafeFileHandle when it's available and go back to IntPtr overload if not available
|
|
|
+ private static readonly ConstructorInfo FileStreamCtor = new[]
|
|
|
+ {
|
|
|
+ AccessTools.Constructor(typeof(FileStream), new[] { typeof(SafeFileHandle), typeof(FileAccess) }),
|
|
|
+ AccessTools.Constructor(typeof(FileStream), new[] { typeof(IntPtr), typeof(FileAccess) }),
|
|
|
+ }.FirstOrDefault(m => m != null);
|
|
|
+
|
|
|
+ private static FileStream OpenFileStream(IntPtr handle)
|
|
|
+ {
|
|
|
+ var fileHandle = new SafeFileHandle(handle, false);
|
|
|
+ var ctorParams = AccessTools.ActualParameters(FileStreamCtor, new object[] { fileHandle, fileHandle.DangerousGetHandle(), FileAccess.Write });
|
|
|
+ return (FileStream)Activator.CreateInstance(typeof(FileStream), ctorParams);
|
|
|
+ }
|
|
|
+
|
|
|
public void CreateConsole(uint codepage)
|
|
|
{
|
|
|
- // On some Unity mono builds the SafeFileHandle overload for FileStream is missing
|
|
|
- // so we use the older but always included one instead
|
|
|
-#pragma warning disable 618
|
|
|
ConsoleWindow.Attach();
|
|
|
|
|
|
// Make sure of ConsoleEncoding helper class because on some Monos
|
|
|
// Encoding.GetEncoding throws NotImplementedException on most codepages
|
|
|
// NOTE: We don't set Console.OutputEncoding because it resets any existing Console.Out writers
|
|
|
ConsoleEncoding.ConsoleCodePage = codepage;
|
|
|
-
|
|
|
+
|
|
|
// If stdout exists, write to it, otherwise make it the same as console out
|
|
|
// Not sure if this is needed? Does the original Console.Out still work?
|
|
|
var stdout = GetOutHandle();
|
|
@@ -49,22 +61,19 @@ namespace BepInEx
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
- _originalOutHandle = new SafeFileHandle(stdout, false);
|
|
|
- var originalOutStream = new FileStream(_originalOutHandle.DangerousGetHandle(), FileAccess.Write);
|
|
|
+ var originalOutStream = OpenFileStream(stdout);
|
|
|
StandardOut = new StreamWriter(originalOutStream, new UTF8Encoding(false))
|
|
|
{
|
|
|
AutoFlush = true
|
|
|
};
|
|
|
|
|
|
- _consoleOutHandle = new SafeFileHandle(ConsoleWindow.ConsoleOutHandle, false);
|
|
|
- var consoleOutStream = new FileStream(_consoleOutHandle.DangerousGetHandle(), FileAccess.Write);
|
|
|
+ var consoleOutStream = OpenFileStream(ConsoleWindow.ConsoleOutHandle);
|
|
|
// Can't use Console.OutputEncoding because it can be null (i.e. not preference by user)
|
|
|
ConsoleOut = new StreamWriter(consoleOutStream, ConsoleEncoding.OutputEncoding)
|
|
|
{
|
|
|
AutoFlush = true
|
|
|
};
|
|
|
ConsoleActive = true;
|
|
|
-#pragma warning restore 618
|
|
|
}
|
|
|
|
|
|
private IntPtr GetOutHandle()
|