You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

107 lines
3.5 KiB

6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
  1. using System;
  2. using System.IO;
  3. using System.Runtime.InteropServices;
  4. using IPA.Logging;
  5. using Microsoft.Win32.SafeHandles;
  6. namespace IPA.Injector
  7. {
  8. // https://stackoverflow.com/a/48864902/3117125
  9. internal static class WinConsole
  10. {
  11. public static void Initialize(bool alwaysCreateNewConsole = true)
  12. {
  13. bool consoleAttached = true;
  14. if (alwaysCreateNewConsole
  15. || (AttachConsole(AttachParent) == 0
  16. && Marshal.GetLastWin32Error() != ErrorAccessDenied))
  17. {
  18. consoleAttached = AllocConsole() != 0;
  19. }
  20. if (consoleAttached)
  21. {
  22. InitializeStreams();
  23. }
  24. }
  25. public static void InitializeStreams()
  26. {
  27. InitializeOutStream();
  28. InitializeInStream();
  29. }
  30. private static void InitializeOutStream()
  31. {
  32. var fs = CreateFileStream("CONOUT$", GenericWrite, FileShareWrite, FileAccess.Write);
  33. if (fs != null)
  34. {
  35. var writer = new StreamWriter(fs) { AutoFlush = true };
  36. Console.SetOut(writer);
  37. Console.SetError(writer);
  38. }
  39. }
  40. private static void InitializeInStream()
  41. {
  42. var fs = CreateFileStream("CONIN$", GenericRead, FileShareRead, FileAccess.Read);
  43. if (fs != null)
  44. {
  45. Console.SetIn(new StreamReader(fs));
  46. }
  47. }
  48. private static FileStream CreateFileStream(string name, uint win32DesiredAccess, uint win32ShareMode,
  49. FileAccess dotNetFileAccess)
  50. {
  51. var file = new SafeFileHandle(CreateFileW(name, win32DesiredAccess, win32ShareMode, IntPtr.Zero, OpenExisting, FileAttributeNormal, IntPtr.Zero), true);
  52. if (!file.IsInvalid)
  53. {
  54. var fs = new FileStream(file, dotNetFileAccess);
  55. return fs;
  56. }
  57. return null;
  58. }
  59. #region Win API Functions and Constants
  60. [DllImport("kernel32.dll",
  61. EntryPoint = "AllocConsole",
  62. SetLastError = true,
  63. CharSet = CharSet.Auto,
  64. CallingConvention = CallingConvention.StdCall)]
  65. private static extern int AllocConsole();
  66. [DllImport("kernel32.dll",
  67. EntryPoint = "AttachConsole",
  68. SetLastError = true,
  69. CharSet = CharSet.Auto,
  70. CallingConvention = CallingConvention.StdCall)]
  71. private static extern uint AttachConsole(uint dwProcessId);
  72. [DllImport("kernel32.dll",
  73. EntryPoint = "CreateFileW",
  74. SetLastError = true,
  75. CharSet = CharSet.Unicode,
  76. CallingConvention = CallingConvention.StdCall)]
  77. private static extern IntPtr CreateFileW(
  78. string lpFileName,
  79. uint dwDesiredAccess,
  80. uint dwShareMode,
  81. IntPtr lpSecurityAttributes,
  82. uint dwCreationDisposition,
  83. uint dwFlagsAndAttributes,
  84. IntPtr hTemplateFile
  85. );
  86. private const uint GenericWrite = 0x40000000;
  87. private const uint GenericRead = 0x80000000;
  88. private const uint FileShareRead = 0x00000001;
  89. private const uint FileShareWrite = 0x00000002;
  90. private const uint OpenExisting = 0x00000003;
  91. private const uint FileAttributeNormal = 0x80;
  92. private const uint ErrorAccessDenied = 5;
  93. private const uint AttachParent = 0xFFFFFFFF;
  94. #endregion
  95. }
  96. }