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.

108 lines
3.6 KiB

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