Browse Source

Initial abstraction of console related calls

Bepis 4 years ago
parent
commit
d2afe06f5b

+ 2 - 3
BepInEx.Preloader/Logger/PreloaderLogWriter.cs

@@ -2,7 +2,6 @@
 using System.Collections.Generic;
 using System.IO;
 using System.Text;
-using BepInEx.ConsoleUtil;
 using BepInEx.Logging;
 
 namespace BepInEx.Preloader
@@ -37,9 +36,9 @@ namespace BepInEx.Preloader
 
 			LogBuilder.Append(log);
 
-			Kon.ForegroundColor = eventArgs.Level.GetConsoleColor();
+			ConsoleManager.SetConsoleColor(eventArgs.Level.GetConsoleColor());
 			ConsoleDirectWrite(log);
-			Kon.ForegroundColor = ConsoleColor.Gray;
+			ConsoleManager.SetConsoleColor(ConsoleColor.Gray);
 		}
 
 		public void ConsoleDirectWrite(string value)

+ 9 - 14
BepInEx.Preloader/Preloader.cs

@@ -3,7 +3,6 @@ using System.Collections.Generic;
 using System.Diagnostics;
 using System.IO;
 using System.Linq;
-using System.Text;
 using BepInEx.Configuration;
 using BepInEx.Logging;
 using BepInEx.Preloader.Patching;
@@ -12,7 +11,6 @@ using HarmonyLib;
 using Mono.Cecil;
 using Mono.Cecil.Cil;
 using MonoMod.RuntimeDetour;
-using UnityInjector.ConsoleUtil;
 using MethodAttributes = Mono.Cecil.MethodAttributes;
 
 namespace BepInEx.Preloader
@@ -33,6 +31,7 @@ namespace BepInEx.Preloader
 		{
 			try
 			{
+				ConsoleManager.Initialize(false);
 				AllocateConsole();
 
 				bool bridgeInitialized = Utility.TryDo(() =>
@@ -57,7 +56,10 @@ namespace BepInEx.Preloader
 				Logger.Listeners.Add(PreloaderLog);
 
 				string consoleTile = $"BepInEx {typeof(Paths).Assembly.GetName().Version} - {Process.GetCurrentProcess().ProcessName}";
-				ConsoleWindow.Title = consoleTile;
+
+				if (ConsoleManager.ConsoleActive)
+					ConsoleManager.SetConsoleTitle(consoleTile);
+
 				Logger.LogMessage(consoleTile);
 
 				//See BuildInfoAttribute for more information about this section.
@@ -112,7 +114,7 @@ namespace BepInEx.Preloader
 
 					PreloaderLog?.Dispose();
 
-					if (!ConsoleWindow.IsAttached)
+					if (!ConsoleManager.ConsoleActive)
 					{
 						//if we've already attached the console, then the log will already be written to the console
 						AllocateConsole();
@@ -222,20 +224,13 @@ namespace BepInEx.Preloader
 		/// </summary>
 		public static void AllocateConsole()
 		{
-			if (!ConsoleWindow.ConfigConsoleEnabled.Value)
+			if (!ConsoleManager.ConfigConsoleEnabled.Value)
 				return;
 
 			try
 			{
-				ConsoleWindow.Attach();
-
-				var encoding = (uint)Encoding.UTF8.CodePage;
-
-				if (ConsoleWindow.ConfigConsoleShiftJis.Value)
-					encoding = 932;
-
-				ConsoleEncoding.ConsoleCodePage = encoding;
-				Console.OutputEncoding = ConsoleEncoding.GetEncoding(encoding);
+				ConsoleManager.CreateConsole();
+				ConsoleManager.SetConsoleEncoding();
 			}
 			catch (Exception ex)
 			{

+ 8 - 6
BepInEx/BepInEx.csproj

@@ -62,6 +62,7 @@
     <Compile Include="Configuration\AcceptableValueList.cs" />
     <Compile Include="Configuration\AcceptableValueRange.cs" />
     <Compile Include="Configuration\ConfigEntryBase.cs" />
+    <Compile Include="Console\ConsoleManager.cs" />
     <Compile Include="Contract\PluginInfo.cs" />
     <Compile Include="Configuration\ConfigDefinition.cs" />
     <Compile Include="Configuration\ConfigDescription.cs" />
@@ -72,12 +73,12 @@
     <Compile Include="Configuration\TomlTypeConverter.cs" />
     <Compile Include="Configuration\TypeConverter.cs" />
     <Compile Include="Contract\Attributes.cs" />
-    <Compile Include="ConsoleUtil\ConsoleEncoding\ConsoleEncoding.Buffers.cs" />
-    <Compile Include="ConsoleUtil\ConsoleEncoding\ConsoleEncoding.cs" />
-    <Compile Include="ConsoleUtil\ConsoleEncoding\ConsoleEncoding.PInvoke.cs" />
-    <Compile Include="ConsoleUtil\ConsoleWindow.cs" />
-    <Compile Include="ConsoleUtil\Kon.cs" />
-    <Compile Include="ConsoleUtil\SafeConsole.cs" />
+    <Compile Include="Console\Windows\ConsoleEncoding\ConsoleEncoding.Buffers.cs" />
+    <Compile Include="Console\Windows\ConsoleEncoding\ConsoleEncoding.cs" />
+    <Compile Include="Console\Windows\ConsoleEncoding\ConsoleEncoding.PInvoke.cs" />
+    <Compile Include="Console\Windows\ConsoleWindow.cs" />
+    <Compile Include="Console\Windows\Kon.cs" />
+    <Compile Include="Console\Windows\SafeConsole.cs" />
     <Compile Include="Bootstrap\Chainloader.cs" />
     <Compile Include="Contract\BaseUnityPlugin.cs" />
     <Compile Include="Logging\DiskLogListener.cs" />
@@ -110,5 +111,6 @@
   <ItemGroup>
     <None Include="packages.config" />
   </ItemGroup>
+  <ItemGroup />
   <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
 </Project>

+ 15 - 14
BepInEx/Bootstrap/Chainloader.cs

@@ -6,11 +6,9 @@ using System.Diagnostics;
 using System.IO;
 using System.Linq;
 using System.Reflection;
-using System.Text;
 using System.Text.RegularExpressions;
 using Mono.Cecil;
 using UnityEngine;
-using UnityInjector.ConsoleUtil;
 using Logger = BepInEx.Logging.Logger;
 
 namespace BepInEx.Bootstrap
@@ -69,20 +67,17 @@ namespace BepInEx.Bootstrap
 			}
 
 			// Start logging
-			if (ConsoleWindow.ConfigConsoleEnabled.Value && startConsole)
+			if (ConsoleManager.ConfigConsoleEnabled.Value && startConsole)
 			{
-				ConsoleWindow.Attach();
+				ConsoleManager.CreateConsole();
 				Logger.Listeners.Add(new ConsoleLogListener());
 			}
 
 			// Fix for standard output getting overwritten by UnityLogger
-			if (ConsoleWindow.StandardOut != null)
+			if (ConsoleManager.ConsoleActive)
 			{
-				Console.SetOut(ConsoleWindow.StandardOut);
-
-				var encoding = ConsoleWindow.ConfigConsoleShiftJis.Value ? 932 : (uint)Encoding.UTF8.CodePage;
-				ConsoleEncoding.ConsoleCodePage = encoding;
-				Console.OutputEncoding = ConsoleEncoding.GetEncoding(encoding);
+				ConsoleManager.SetConsoleStreams();
+				ConsoleManager.SetConsoleEncoding();
 			}
 
 			Logger.Listeners.Add(new UnityLogListener());
@@ -227,7 +222,9 @@ namespace BepInEx.Bootstrap
 			try
 			{
 				var productNameProp = typeof(Application).GetProperty("productName", BindingFlags.Public | BindingFlags.Static);
-				ConsoleWindow.Title = $"{CurrentAssemblyName} {CurrentAssemblyVersion} - {productNameProp?.GetValue(null, null) ?? Process.GetCurrentProcess().ProcessName}";
+
+				if (ConsoleManager.ConsoleActive)
+					ConsoleManager.SetConsoleTitle($"{CurrentAssemblyName} {CurrentAssemblyVersion} - {productNameProp?.GetValue(null, null) ?? Process.GetCurrentProcess().ProcessName}");
 
 				Logger.LogMessage("Chainloader started");
 
@@ -384,10 +381,14 @@ namespace BepInEx.Bootstrap
 			}
 			catch (Exception ex)
 			{
-				ConsoleWindow.Attach();
+				try
+				{
+					ConsoleManager.CreateConsole();
+				}
+				catch { }
 
-				Console.WriteLine("Error occurred starting the game");
-				Console.WriteLine(ex.ToString());
+				Logger.LogFatal("Error occurred starting the game");
+				Logger.LogFatal(ex.ToString());
 			}
 
 			Logger.LogMessage("Chainloader startup complete");

+ 183 - 0
BepInEx/Console/ConsoleManager.cs

@@ -0,0 +1,183 @@
+using System;
+using System.IO;
+using System.Text;
+using BepInEx.Configuration;
+using BepInEx.ConsoleUtil;
+using UnityInjector.ConsoleUtil;
+
+namespace BepInEx
+{
+	public static class ConsoleManager
+	{
+		/// <summary>
+		/// True if an external console has been started, false otherwise.
+		/// </summary>
+		public static bool ConsoleActive { get; private set; }
+
+		/// <summary>
+		/// The stream that writes to the standard out stream of the process. Should never be null.
+		/// </summary>
+		public static TextWriter StandardOutStream { get; internal set; }
+
+		/// <summary>
+		/// The stream that writes to an external console. Null if no such console exists
+		/// </summary>
+		public static TextWriter ConsoleStream { get; internal set; }
+
+
+		public static void Initialize(bool active)
+		{
+			StandardOutStream = Console.Out;
+			Console.SetOut(StandardOutStream);
+			ConsoleActive = active;
+
+			switch (Environment.OSVersion.Platform)
+			{
+				case PlatformID.MacOSX:
+				case PlatformID.Unix:
+				{
+					ConsoleActive = true;
+					break;
+				}
+			}
+		}
+
+
+		public static void CreateConsole()
+		{
+			if (ConsoleActive)
+				return;
+			
+			switch (Environment.OSVersion.Platform)
+			{
+				case PlatformID.Win32NT:
+				{
+					ConsoleWindow.Attach();
+					break;
+				}
+
+				default:
+					throw new PlatformNotSupportedException("Spawning a console is not currently supported on this platform");
+			}
+
+			SetConsoleStreams();
+
+			ConsoleActive = true;
+		}
+
+		public static void DetachConsole()
+		{
+			if (!ConsoleActive)
+				return;
+
+			switch (Environment.OSVersion.Platform)
+			{
+				case PlatformID.Win32NT:
+				{
+					ConsoleWindow.Detach();
+					break;
+				}
+
+				default:
+					throw new PlatformNotSupportedException("Spawning a console is not currently supported on this platform");
+			}
+
+			ConsoleActive = false;
+		}
+
+		public static void SetConsoleEncoding()
+		{
+			uint encoding = ConfigConsoleShiftJis.Value ? 932 : (uint)Encoding.UTF8.CodePage;
+
+			SetConsoleEncoding(encoding);
+		}
+
+		public static void SetConsoleEncoding(uint encodingCodePage)
+		{
+			if (!ConsoleActive)
+				throw new InvalidOperationException("Console is not currently active");
+
+			switch (Environment.OSVersion.Platform)
+			{
+				case PlatformID.Win32NT:
+				{
+					ConsoleEncoding.ConsoleCodePage = encodingCodePage;
+					Console.OutputEncoding = Encoding.GetEncoding((int)encodingCodePage);
+					break;
+				}
+
+				case PlatformID.MacOSX:
+				case PlatformID.Unix:
+				{
+					break;
+				}
+			}
+		}
+
+		public static void SetConsoleTitle(string title)
+		{
+			switch (Environment.OSVersion.Platform)
+			{
+				case PlatformID.Win32NT:
+				{
+					if (!ConsoleActive)
+						return;
+
+					ConsoleWindow.Title = title;
+					break;
+				}
+			}
+		}
+
+		public static void SetConsoleColor(ConsoleColor color)
+		{
+			switch (Environment.OSVersion.Platform)
+			{
+				case PlatformID.Win32NT:
+				{
+					if (!ConsoleActive)
+						return;
+
+					Kon.ForegroundColor = color;
+					break;
+				}
+			}
+
+			Console.ForegroundColor = color;
+		}
+
+		internal static void SetConsoleStreams()
+		{
+			switch (Environment.OSVersion.Platform)
+			{
+				case PlatformID.Win32NT:
+				{
+					Console.SetOut(ConsoleStream);
+					Console.SetError(ConsoleStream);
+					break;
+				}
+
+				case PlatformID.MacOSX:
+				case PlatformID.Unix:
+				{
+					// We do not have external consoles on Unix platforms.
+					// Set the console output to standard output
+
+					Console.SetOut(StandardOutStream);
+					Console.SetError(StandardOutStream);
+					break;
+				}
+			}
+		}
+
+		public static readonly ConfigEntry<bool> ConfigConsoleEnabled = ConfigFile.CoreConfig.Bind(
+			"Logging.Console", "Enabled",
+			false,
+			"Enables showing a console for log output.");
+
+		public static readonly ConfigEntry<bool> ConfigConsoleShiftJis = ConfigFile.CoreConfig.Bind(
+			"Logging.Console", "ShiftJisEncoding",
+			false,
+			"If true, console is set to the Shift-JIS encoding, otherwise UTF-8 encoding.");
+	}
+}

BepInEx/ConsoleUtil/ConsoleEncoding/ConsoleEncoding.Buffers.cs → BepInEx/Console/Windows/ConsoleEncoding/ConsoleEncoding.Buffers.cs


BepInEx/ConsoleUtil/ConsoleEncoding/ConsoleEncoding.PInvoke.cs → BepInEx/Console/Windows/ConsoleEncoding/ConsoleEncoding.PInvoke.cs


BepInEx/ConsoleUtil/ConsoleEncoding/ConsoleEncoding.cs → BepInEx/Console/Windows/ConsoleEncoding/ConsoleEncoding.cs


+ 9 - 16
BepInEx/ConsoleUtil/ConsoleWindow.cs

@@ -7,28 +7,17 @@ using System;
 using System.IO;
 using System.Runtime.InteropServices;
 using System.Text;
-using BepInEx.Configuration;
+using BepInEx;
+using Microsoft.Win32.SafeHandles;
 
 namespace UnityInjector.ConsoleUtil
 {
 	internal class ConsoleWindow
 	{
-		public static readonly ConfigEntry<bool> ConfigConsoleEnabled = ConfigFile.CoreConfig.Bind(
-			"Logging.Console", "Enabled",
-			false,
-			"Enables showing a console for log output.");
-
-		public static readonly ConfigEntry<bool> ConfigConsoleShiftJis = ConfigFile.CoreConfig.Bind(
-			"Logging.Console", "ShiftJisEncoding",
-			false,
-			"If true, console is set to the Shift-JIS encoding, otherwise UTF-8 encoding.");
-
 		public static bool IsAttached { get; private set; }
 		private static IntPtr _cOut;
 		private static IntPtr _oOut;
 
-		public static TextWriter StandardOut { get; private set; }
-
 		public static void Attach()
 		{
 			if (IsAttached)
@@ -53,6 +42,10 @@ namespace UnityInjector.ConsoleUtil
 
 			if (!SetStdHandle(-11, _cOut))
 				throw new Exception("SetStdHandle() failed");
+
+			var originalOutStream = new FileStream(new SafeFileHandle(_oOut, false), FileAccess.Write);
+			ConsoleManager.StandardOutStream = new StreamWriter(originalOutStream, new UTF8Encoding(false));
+
 			Init();
 
 			IsAttached = true;
@@ -134,13 +127,13 @@ namespace UnityInjector.ConsoleUtil
 		private static void Init()
 		{
 			var stdOut = Console.OpenStandardOutput();
-			StandardOut = new StreamWriter(stdOut, Encoding.Default)
+			ConsoleManager.ConsoleStream = new StreamWriter(stdOut, Encoding.Default)
 			{
 				AutoFlush = true
 			};
 
-			Console.SetOut(StandardOut);
-			Console.SetError(StandardOut);
+			Console.SetOut(ConsoleManager.ConsoleStream);
+			Console.SetError(ConsoleManager.ConsoleStream);
 		}
 
 		[DllImport("kernel32.dll", SetLastError = true)]

+ 11 - 19
BepInEx/ConsoleUtil/Kon.cs

@@ -64,27 +64,19 @@ namespace BepInEx.ConsoleUtil
 			succeeded = false;
 			if (!(conOut == INVALID_HANDLE_VALUE))
 			{
-				try
+				CONSOLE_SCREEN_BUFFER_INFO console_SCREEN_BUFFER_INFO;
+				if (!GetConsoleScreenBufferInfo(conOut, out console_SCREEN_BUFFER_INFO))
 				{
-					// FIXME: Windows console shouldn't be used in other OSs in the first place
-					CONSOLE_SCREEN_BUFFER_INFO console_SCREEN_BUFFER_INFO;
-					if (!GetConsoleScreenBufferInfo(conOut, out console_SCREEN_BUFFER_INFO))
-					{
-						bool consoleScreenBufferInfo = GetConsoleScreenBufferInfo(GetStdHandle(-12), out console_SCREEN_BUFFER_INFO);
-						if (!consoleScreenBufferInfo)
-							consoleScreenBufferInfo = GetConsoleScreenBufferInfo(GetStdHandle(-10), out console_SCREEN_BUFFER_INFO);
-						
-						if (!consoleScreenBufferInfo)
-							if (Marshal.GetLastWin32Error() == 6 && !throwOnNoConsole)
-								return default(CONSOLE_SCREEN_BUFFER_INFO);
-					}
-					succeeded = true;
-					return console_SCREEN_BUFFER_INFO;
-				}
-				catch (EntryPointNotFoundException)
-				{
-					// Fails under unsupported OSes
+					bool consoleScreenBufferInfo = GetConsoleScreenBufferInfo(GetStdHandle(-12), out console_SCREEN_BUFFER_INFO);
+					if (!consoleScreenBufferInfo)
+						consoleScreenBufferInfo = GetConsoleScreenBufferInfo(GetStdHandle(-10), out console_SCREEN_BUFFER_INFO);
+					
+					if (!consoleScreenBufferInfo)
+						if (Marshal.GetLastWin32Error() == 6 && !throwOnNoConsole)
+							return default(CONSOLE_SCREEN_BUFFER_INFO);
 				}
+				succeeded = true;
+				return console_SCREEN_BUFFER_INFO;
 			}
 
 			if (!throwOnNoConsole)

BepInEx/ConsoleUtil/SafeConsole.cs → BepInEx/Console/Windows/SafeConsole.cs


+ 2 - 3
BepInEx/Logging/ConsoleLogListener.cs

@@ -1,6 +1,5 @@
 using System;
 using BepInEx.Configuration;
-using BepInEx.ConsoleUtil;
 
 namespace BepInEx.Logging
 {
@@ -16,9 +15,9 @@ namespace BepInEx.Logging
 
 			string log = $"[{eventArgs.Level,-7}:{((ILogSource)sender).SourceName,10}] {eventArgs.Data}\r\n";
 
-			Kon.ForegroundColor = eventArgs.Level.GetConsoleColor();
+			ConsoleManager.SetConsoleColor(eventArgs.Level.GetConsoleColor());
 			Console.Write(log);
-			Kon.ForegroundColor = ConsoleColor.Gray;
+			ConsoleManager.SetConsoleColor(ConsoleColor.Gray);
 		}
 
 		public void Dispose() { }