ConsoleWindow.cs 4.2 KB

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