WindowsConsoleDriver.cs 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105
  1. using System;
  2. using System.IO;
  3. using System.Text;
  4. using BepInEx.ConsoleUtil;
  5. using Microsoft.Win32.SafeHandles;
  6. using UnityInjector.ConsoleUtil;
  7. namespace BepInEx
  8. {
  9. internal class WindowsConsoleDriver : IConsoleDriver
  10. {
  11. // We need to save stdout and conout as SafeFileHandles because we can't pass it to FileStream (check comments in CreateConsole)
  12. // However, on some versions of Unity (e.g. 2018.4) using old mono causes crashes on game close if
  13. // the stdout and conout are not saved into a file handle (check #139)
  14. private SafeFileHandle _originalOutHandle, _consoleOutHandle;
  15. public TextWriter StandardOut { get; private set; }
  16. public TextWriter ConsoleOut { get; private set; }
  17. public bool ConsoleActive { get; private set; }
  18. public bool ConsoleIsExternal => true;
  19. public void Initialize(bool alreadyActive)
  20. {
  21. ConsoleActive = alreadyActive;
  22. StandardOut = Console.Out;
  23. }
  24. public void CreateConsole(uint codepage)
  25. {
  26. // On some Unity mono builds the SafeFileHandle overload for FileStream is missing
  27. // so we use the older but always included one instead
  28. #pragma warning disable 618
  29. ConsoleWindow.Attach();
  30. // Make sure of ConsoleEncoding helper class because on some Monos
  31. // Encoding.GetEncoding throws NotImplementedException on most codepages
  32. // NOTE: We don't set Console.OutputEncoding because it resets any existing Console.Out writers
  33. ConsoleEncoding.ConsoleCodePage = codepage;
  34. // If stdout exists, write to it, otherwise make it the same as console out
  35. // Not sure if this is needed? Does the original Console.Out still work?
  36. var stdout = GetOutHandle();
  37. if (stdout == IntPtr.Zero)
  38. {
  39. StandardOut = TextWriter.Null;
  40. ConsoleOut = TextWriter.Null;
  41. return;
  42. }
  43. _originalOutHandle = new SafeFileHandle(stdout, false);
  44. var originalOutStream = new FileStream(_originalOutHandle.DangerousGetHandle(), FileAccess.Write);
  45. StandardOut = new StreamWriter(originalOutStream, new UTF8Encoding(false))
  46. {
  47. AutoFlush = true
  48. };
  49. _consoleOutHandle = new SafeFileHandle(ConsoleWindow.ConsoleOutHandle, false);
  50. var consoleOutStream = new FileStream(_consoleOutHandle.DangerousGetHandle(), FileAccess.Write);
  51. // Can't use Console.OutputEncoding because it can be null (i.e. not preference by user)
  52. ConsoleOut = new StreamWriter(consoleOutStream, ConsoleEncoding.OutputEncoding)
  53. {
  54. AutoFlush = true
  55. };
  56. ConsoleActive = true;
  57. #pragma warning restore 618
  58. }
  59. private IntPtr GetOutHandle()
  60. {
  61. switch (ConsoleManager.ConfigConsoleOutRedirectType.Value)
  62. {
  63. case ConsoleManager.ConsoleOutRedirectType.ConsoleOut:
  64. return ConsoleWindow.ConsoleOutHandle;
  65. case ConsoleManager.ConsoleOutRedirectType.StandardOut:
  66. return ConsoleWindow.OriginalStdoutHandle;
  67. case ConsoleManager.ConsoleOutRedirectType.Auto:
  68. default:
  69. return ConsoleWindow.OriginalStdoutHandle != IntPtr.Zero ? ConsoleWindow.OriginalStdoutHandle : ConsoleWindow.ConsoleOutHandle;
  70. }
  71. }
  72. public void DetachConsole()
  73. {
  74. ConsoleWindow.Detach();
  75. ConsoleOut.Close();
  76. ConsoleOut = null;
  77. ConsoleActive = false;
  78. }
  79. public void SetConsoleColor(ConsoleColor color)
  80. {
  81. SafeConsole.ForegroundColor = color;
  82. Kon.ForegroundColor = color;
  83. }
  84. public void SetConsoleTitle(string title)
  85. {
  86. ConsoleWindow.Title = title;
  87. }
  88. }
  89. }