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.

103 lines
3.5 KiB

6 years ago
6 years ago
6 years ago
6 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. InitializeOutStream();
  24. InitializeInStream();
  25. }
  26. }
  27. private static void InitializeOutStream()
  28. {
  29. var fs = CreateFileStream("CONOUT$", GENERIC_WRITE, FILE_SHARE_WRITE, FileAccess.Write);
  30. if (fs != null)
  31. {
  32. var writer = new StreamWriter(fs) { AutoFlush = true };
  33. Console.SetOut(writer);
  34. Console.SetError(writer);
  35. }
  36. }
  37. private static void InitializeInStream()
  38. {
  39. var fs = CreateFileStream("CONIN$", GENERIC_READ, FILE_SHARE_READ, FileAccess.Read);
  40. if (fs != null)
  41. {
  42. Console.SetIn(new StreamReader(fs));
  43. }
  44. }
  45. private static FileStream CreateFileStream(string name, uint win32DesiredAccess, uint win32ShareMode,
  46. FileAccess dotNetFileAccess)
  47. {
  48. var file = new SafeFileHandle(CreateFileW(name, win32DesiredAccess, win32ShareMode, IntPtr.Zero, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, IntPtr.Zero), true);
  49. if (!file.IsInvalid)
  50. {
  51. var fs = new FileStream(file, dotNetFileAccess);
  52. return fs;
  53. }
  54. return null;
  55. }
  56. #region Win API Functions and Constants
  57. [DllImport("kernel32.dll",
  58. EntryPoint = "AllocConsole",
  59. SetLastError = true,
  60. CharSet = CharSet.Auto,
  61. CallingConvention = CallingConvention.StdCall)]
  62. private static extern int AllocConsole();
  63. [DllImport("kernel32.dll",
  64. EntryPoint = "AttachConsole",
  65. SetLastError = true,
  66. CharSet = CharSet.Auto,
  67. CallingConvention = CallingConvention.StdCall)]
  68. private static extern UInt32 AttachConsole(UInt32 dwProcessId);
  69. [DllImport("kernel32.dll",
  70. EntryPoint = "CreateFileW",
  71. SetLastError = true,
  72. CharSet = CharSet.Unicode,
  73. CallingConvention = CallingConvention.StdCall)]
  74. private static extern IntPtr CreateFileW(
  75. string lpFileName,
  76. UInt32 dwDesiredAccess,
  77. UInt32 dwShareMode,
  78. IntPtr lpSecurityAttributes,
  79. UInt32 dwCreationDisposition,
  80. UInt32 dwFlagsAndAttributes,
  81. IntPtr hTemplateFile
  82. );
  83. private const UInt32 GENERIC_WRITE = 0x40000000;
  84. private const UInt32 GENERIC_READ = 0x80000000;
  85. private const UInt32 FILE_SHARE_READ = 0x00000001;
  86. private const UInt32 FILE_SHARE_WRITE = 0x00000002;
  87. private const UInt32 OPEN_EXISTING = 0x00000003;
  88. private const UInt32 FILE_ATTRIBUTE_NORMAL = 0x80;
  89. private const UInt32 ERROR_ACCESS_DENIED = 5;
  90. private const UInt32 ATTACH_PARRENT = 0xFFFFFFFF;
  91. #endregion
  92. }
  93. }