ConsoleWindow.cs 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145
  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;
  10. using Microsoft.Win32.SafeHandles;
  11. namespace UnityInjector.ConsoleUtil
  12. {
  13. internal class ConsoleWindow
  14. {
  15. public static bool IsAttached { get; private set; }
  16. private static IntPtr _cOut;
  17. private static IntPtr _oOut;
  18. public static void Attach()
  19. {
  20. if (IsAttached)
  21. return;
  22. if (_oOut == IntPtr.Zero)
  23. _oOut = GetStdHandle(-11);
  24. // Store Current Window
  25. IntPtr currWnd = GetForegroundWindow();
  26. //Check for existing console before allocating
  27. if (GetConsoleWindow() == IntPtr.Zero)
  28. if (!AllocConsole())
  29. throw new Exception("AllocConsole() failed");
  30. // Restore Foreground
  31. SetForegroundWindow(currWnd);
  32. _cOut = CreateFile("CONOUT$", 0x80000000 | 0x40000000, 2, IntPtr.Zero, 3, 0, IntPtr.Zero);
  33. BepInEx.ConsoleUtil.Kon.conOut = _cOut;
  34. if (!SetStdHandle(-11, _cOut))
  35. throw new Exception("SetStdHandle() failed");
  36. var originalOutStream = new FileStream(new SafeFileHandle(_oOut, false), FileAccess.Write);
  37. ConsoleManager.StandardOutStream = new StreamWriter(originalOutStream, new UTF8Encoding(false));
  38. Init();
  39. IsAttached = true;
  40. }
  41. public static string Title
  42. {
  43. set
  44. {
  45. if (!IsAttached)
  46. return;
  47. if (value == null)
  48. {
  49. throw new ArgumentNullException(nameof(value));
  50. }
  51. if (value.Length > 24500)
  52. {
  53. throw new InvalidOperationException("Console title too long");
  54. }
  55. if (!SetConsoleTitle(value))
  56. {
  57. throw new InvalidOperationException("Console title invalid");
  58. }
  59. }
  60. }
  61. public static void Detach()
  62. {
  63. if (!IsAttached)
  64. return;
  65. if (!CloseHandle(_cOut))
  66. throw new Exception("CloseHandle() failed");
  67. _cOut = IntPtr.Zero;
  68. if (!FreeConsole())
  69. throw new Exception("FreeConsole() failed");
  70. if (!SetStdHandle(-11, _oOut))
  71. throw new Exception("SetStdHandle() failed");
  72. Init();
  73. IsAttached = false;
  74. }
  75. [DllImport("user32.dll")]
  76. private static extern IntPtr GetForegroundWindow();
  77. [DllImport("user32.dll")]
  78. [return: MarshalAs(UnmanagedType.Bool)]
  79. private static extern bool SetForegroundWindow(IntPtr hWnd);
  80. [DllImport("kernel32.dll", SetLastError = true)]
  81. private static extern bool AllocConsole();
  82. [DllImport("kernel32.dll")]
  83. private static extern IntPtr GetConsoleWindow();
  84. [DllImport("kernel32.dll", ExactSpelling = true, SetLastError = true)]
  85. private static extern bool CloseHandle(IntPtr handle);
  86. [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
  87. private static extern IntPtr CreateFile(
  88. string fileName,
  89. uint desiredAccess,
  90. int shareMode,
  91. IntPtr securityAttributes,
  92. int creationDisposition,
  93. int flagsAndAttributes,
  94. IntPtr templateFile);
  95. [DllImport("kernel32.dll", SetLastError = false)]
  96. private static extern bool FreeConsole();
  97. [DllImport("kernel32.dll", SetLastError = true)]
  98. private static extern IntPtr GetStdHandle(int nStdHandle);
  99. private static void Init()
  100. {
  101. var stdOut = Console.OpenStandardOutput();
  102. ConsoleManager.ConsoleStream = new StreamWriter(stdOut, Encoding.Default)
  103. {
  104. AutoFlush = true
  105. };
  106. Console.SetOut(ConsoleManager.ConsoleStream);
  107. Console.SetError(ConsoleManager.ConsoleStream);
  108. }
  109. [DllImport("kernel32.dll", SetLastError = true)]
  110. private static extern bool SetStdHandle(int nStdHandle, IntPtr hConsoleOutput);
  111. [DllImport("kernel32.dll", BestFitMapping = true, CharSet = CharSet.Auto, SetLastError = true)]
  112. private static extern bool SetConsoleTitle(string title);
  113. }
  114. }