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.

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