ConsoleWindow.cs 3.8 KB

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