ConsoleWindow.cs 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154
  1. // --------------------------------------------------
  2. // UnityInjector - ConsoleWindow.cs
  3. // Copyright (c) Usagirei 2015 - 2015
  4. // --------------------------------------------------
  5. using System;
  6. using System.IO;
  7. using System.Runtime.InteropServices;
  8. using System.Text;
  9. using BepInEx.Configuration;
  10. namespace UnityInjector.ConsoleUtil
  11. {
  12. internal class ConsoleWindow
  13. {
  14. public static readonly ConfigWrapper<bool> ConfigConsoleEnabled = ConfigFile.CoreConfig.Wrap(
  15. "Logging.Console",
  16. "Enabled",
  17. "Enables showing a console for log output.",
  18. false);
  19. public static readonly ConfigWrapper<bool> ConfigConsoleShiftJis = ConfigFile.CoreConfig.Wrap(
  20. "Logging.Console",
  21. "ShiftJisEncoding",
  22. "If true, console is set to the Shift-JIS encoding, otherwise UTF-8 encoding.",
  23. false);
  24. public static bool IsAttached { get; private set; }
  25. private static IntPtr _cOut;
  26. private static IntPtr _oOut;
  27. public static TextWriter StandardOut { get; private set; }
  28. public static void Attach()
  29. {
  30. if (IsAttached)
  31. return;
  32. if (_oOut == IntPtr.Zero)
  33. _oOut = GetStdHandle(-11);
  34. // Store Current Window
  35. IntPtr currWnd = GetForegroundWindow();
  36. //Check for existing console before allocating
  37. if (GetConsoleWindow() == IntPtr.Zero)
  38. if (!AllocConsole())
  39. throw new Exception("AllocConsole() failed");
  40. // Restore Foreground
  41. SetForegroundWindow(currWnd);
  42. _cOut = CreateFile("CONOUT$", 0x80000000 | 0x40000000, 2, IntPtr.Zero, 3, 0, IntPtr.Zero);
  43. BepInEx.ConsoleUtil.Kon.conOut = _cOut;
  44. if (!SetStdHandle(-11, _cOut))
  45. throw new Exception("SetStdHandle() failed");
  46. Init();
  47. IsAttached = true;
  48. }
  49. public static string Title
  50. {
  51. set
  52. {
  53. if (!IsAttached)
  54. return;
  55. if (value == null)
  56. {
  57. throw new ArgumentNullException(nameof(value));
  58. }
  59. if (value.Length > 24500)
  60. {
  61. throw new InvalidOperationException("Console title too long");
  62. }
  63. if (!SetConsoleTitle(value))
  64. {
  65. throw new InvalidOperationException("Console title invalid");
  66. }
  67. }
  68. }
  69. public static void Detach()
  70. {
  71. if (!IsAttached)
  72. return;
  73. if (!CloseHandle(_cOut))
  74. throw new Exception("CloseHandle() failed");
  75. _cOut = IntPtr.Zero;
  76. if (!FreeConsole())
  77. throw new Exception("FreeConsole() failed");
  78. if (!SetStdHandle(-11, _oOut))
  79. throw new Exception("SetStdHandle() failed");
  80. Init();
  81. IsAttached = false;
  82. }
  83. [DllImport("user32.dll")]
  84. private static extern IntPtr GetForegroundWindow();
  85. [DllImport("user32.dll")]
  86. [return: MarshalAs(UnmanagedType.Bool)]
  87. static extern bool SetForegroundWindow(IntPtr hWnd);
  88. [DllImport("kernel32.dll", SetLastError = true)]
  89. private static extern bool AllocConsole();
  90. [DllImport("kernel32.dll")]
  91. private static extern IntPtr GetConsoleWindow();
  92. [DllImport("kernel32.dll", ExactSpelling = true, SetLastError = true)]
  93. private static extern bool CloseHandle(IntPtr handle);
  94. [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
  95. private static extern IntPtr CreateFile(
  96. string fileName,
  97. uint desiredAccess,
  98. int shareMode,
  99. IntPtr securityAttributes,
  100. int creationDisposition,
  101. int flagsAndAttributes,
  102. IntPtr templateFile);
  103. [DllImport("kernel32.dll", SetLastError = false)]
  104. private static extern bool FreeConsole();
  105. [DllImport("kernel32.dll", SetLastError = true)]
  106. private static extern IntPtr GetStdHandle(int nStdHandle);
  107. private static void Init()
  108. {
  109. var stdOut = Console.OpenStandardOutput();
  110. StandardOut = new StreamWriter(stdOut, Encoding.Default)
  111. {
  112. AutoFlush = true
  113. };
  114. Console.SetOut(StandardOut);
  115. Console.SetError(StandardOut);
  116. }
  117. [DllImport("kernel32.dll", SetLastError = true)]
  118. private static extern bool SetStdHandle(int nStdHandle, IntPtr hConsoleOutput);
  119. [DllImport("kernel32.dll", BestFitMapping = true, CharSet = CharSet.Auto, SetLastError = true)]
  120. private static extern bool SetConsoleTitle(string title);
  121. }
  122. }