ConsoleWindow.cs 3.5 KB

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