|
@ -7,66 +7,98 @@ using Microsoft.Win32.SafeHandles; |
|
|
|
|
|
|
|
|
namespace Ipa.Injector.Windows |
|
|
namespace Ipa.Injector.Windows |
|
|
{ |
|
|
{ |
|
|
|
|
|
// https://stackoverflow.com/a/48864902/3117125
|
|
|
|
|
|
static class WinConsole |
|
|
|
|
|
{ |
|
|
|
|
|
static public void Initialize(bool alwaysCreateNewConsole = true) |
|
|
|
|
|
{ |
|
|
|
|
|
bool consoleAttached = true; |
|
|
|
|
|
if (alwaysCreateNewConsole |
|
|
|
|
|
|| (AttachConsole(ATTACH_PARRENT) == 0 |
|
|
|
|
|
&& Marshal.GetLastWin32Error() != ERROR_ACCESS_DENIED)) |
|
|
|
|
|
{ |
|
|
|
|
|
consoleAttached = AllocConsole() != 0; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
class GuiConsole |
|
|
|
|
|
{ |
|
|
|
|
|
public static void CreateConsole() |
|
|
|
|
|
{ |
|
|
|
|
|
if (hasConsole) |
|
|
|
|
|
return; |
|
|
|
|
|
if (oldOut == IntPtr.Zero) |
|
|
|
|
|
oldOut = GetStdHandle( -11 ); |
|
|
|
|
|
if (! AllocConsole()) |
|
|
|
|
|
throw new Exception("AllocConsole() failed"); |
|
|
|
|
|
conOut = CreateFile( "CONOUT$", 0x40000000, 2, IntPtr.Zero, 3, 0, IntPtr.Zero ); |
|
|
|
|
|
if (! SetStdHandle(-11, conOut)) |
|
|
|
|
|
throw new Exception("SetStdHandle() failed"); |
|
|
|
|
|
StreamToConsole(); |
|
|
|
|
|
hasConsole = true; |
|
|
|
|
|
} |
|
|
|
|
|
public static void ReleaseConsole() |
|
|
|
|
|
{ |
|
|
|
|
|
if (! hasConsole) |
|
|
|
|
|
return; |
|
|
|
|
|
if (! CloseHandle(conOut)) |
|
|
|
|
|
throw new Exception("CloseHandle() failed"); |
|
|
|
|
|
conOut = IntPtr.Zero; |
|
|
|
|
|
if (! FreeConsole()) |
|
|
|
|
|
throw new Exception("FreeConsole() failed"); |
|
|
|
|
|
if (! SetStdHandle(-11, oldOut)) |
|
|
|
|
|
throw new Exception("SetStdHandle() failed"); |
|
|
|
|
|
StreamToConsole(); |
|
|
|
|
|
hasConsole = false; |
|
|
|
|
|
} |
|
|
|
|
|
private static void StreamToConsole() |
|
|
|
|
|
{ |
|
|
|
|
|
Stream cstm = Console.OpenStandardOutput(); |
|
|
|
|
|
StreamWriter cstw = new StreamWriter( cstm, Encoding.Default ); |
|
|
|
|
|
cstw.AutoFlush = true; |
|
|
|
|
|
Console.SetOut( cstw ); |
|
|
|
|
|
Console.SetError( cstw ); |
|
|
|
|
|
} |
|
|
|
|
|
private static bool hasConsole = false; |
|
|
|
|
|
private static IntPtr conOut; |
|
|
|
|
|
private static IntPtr oldOut; |
|
|
|
|
|
[DllImport("kernel32.dll", SetLastError=true)] |
|
|
|
|
|
private static extern bool AllocConsole(); |
|
|
|
|
|
[DllImport("kernel32.dll", SetLastError=false)] |
|
|
|
|
|
private static extern bool FreeConsole(); |
|
|
|
|
|
[DllImport("kernel32.dll", SetLastError=true)] |
|
|
|
|
|
private static extern IntPtr GetStdHandle( int nStdHandle ); |
|
|
|
|
|
[DllImport("kernel32.dll", SetLastError=true)] |
|
|
|
|
|
private static extern bool SetStdHandle(int nStdHandle, IntPtr hConsoleOutput); |
|
|
|
|
|
[DllImport("kernel32.dll", CharSet=CharSet.Auto, SetLastError=true)] |
|
|
|
|
|
private static extern IntPtr CreateFile( |
|
|
|
|
|
string fileName, |
|
|
|
|
|
int desiredAccess, |
|
|
|
|
|
int shareMode, |
|
|
|
|
|
IntPtr securityAttributes, |
|
|
|
|
|
int creationDisposition, |
|
|
|
|
|
int flagsAndAttributes, |
|
|
|
|
|
IntPtr templateFile ); |
|
|
|
|
|
[DllImport("kernel32.dll", ExactSpelling=true, SetLastError=true)] |
|
|
|
|
|
private static extern bool CloseHandle(IntPtr handle); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
if (consoleAttached) |
|
|
|
|
|
{ |
|
|
|
|
|
InitializeOutStream(); |
|
|
|
|
|
InitializeInStream(); |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
private static void InitializeOutStream() |
|
|
|
|
|
{ |
|
|
|
|
|
var fs = CreateFileStream("CONOUT$", GENERIC_WRITE, FILE_SHARE_WRITE, FileAccess.Write); |
|
|
|
|
|
if (fs != null) |
|
|
|
|
|
{ |
|
|
|
|
|
var writer = new StreamWriter(fs) { AutoFlush = true }; |
|
|
|
|
|
Console.SetOut(writer); |
|
|
|
|
|
Console.SetError(writer); |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
private static void InitializeInStream() |
|
|
|
|
|
{ |
|
|
|
|
|
var fs = CreateFileStream("CONIN$", GENERIC_READ, FILE_SHARE_READ, FileAccess.Read); |
|
|
|
|
|
if (fs != null) |
|
|
|
|
|
{ |
|
|
|
|
|
Console.SetIn(new StreamReader(fs)); |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
private static FileStream CreateFileStream(string name, uint win32DesiredAccess, uint win32ShareMode, |
|
|
|
|
|
FileAccess dotNetFileAccess) |
|
|
|
|
|
{ |
|
|
|
|
|
var file = new SafeFileHandle(CreateFileW(name, win32DesiredAccess, win32ShareMode, IntPtr.Zero, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, IntPtr.Zero), true); |
|
|
|
|
|
if (!file.IsInvalid) |
|
|
|
|
|
{ |
|
|
|
|
|
var fs = new FileStream(file, dotNetFileAccess); |
|
|
|
|
|
return fs; |
|
|
|
|
|
} |
|
|
|
|
|
return null; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
#region Win API Functions and Constants
|
|
|
|
|
|
[DllImport("kernel32.dll", |
|
|
|
|
|
EntryPoint = "AllocConsole", |
|
|
|
|
|
SetLastError = true, |
|
|
|
|
|
CharSet = CharSet.Auto, |
|
|
|
|
|
CallingConvention = CallingConvention.StdCall)] |
|
|
|
|
|
private static extern int AllocConsole(); |
|
|
|
|
|
|
|
|
|
|
|
[DllImport("kernel32.dll", |
|
|
|
|
|
EntryPoint = "AttachConsole", |
|
|
|
|
|
SetLastError = true, |
|
|
|
|
|
CharSet = CharSet.Auto, |
|
|
|
|
|
CallingConvention = CallingConvention.StdCall)] |
|
|
|
|
|
private static extern UInt32 AttachConsole(UInt32 dwProcessId); |
|
|
|
|
|
|
|
|
|
|
|
[DllImport("kernel32.dll", |
|
|
|
|
|
EntryPoint = "CreateFileW", |
|
|
|
|
|
SetLastError = true, |
|
|
|
|
|
CharSet = CharSet.Auto, |
|
|
|
|
|
CallingConvention = CallingConvention.StdCall)] |
|
|
|
|
|
private static extern IntPtr CreateFileW( |
|
|
|
|
|
string lpFileName, |
|
|
|
|
|
UInt32 dwDesiredAccess, |
|
|
|
|
|
UInt32 dwShareMode, |
|
|
|
|
|
IntPtr lpSecurityAttributes, |
|
|
|
|
|
UInt32 dwCreationDisposition, |
|
|
|
|
|
UInt32 dwFlagsAndAttributes, |
|
|
|
|
|
IntPtr hTemplateFile |
|
|
|
|
|
); |
|
|
|
|
|
|
|
|
|
|
|
private const UInt32 GENERIC_WRITE = 0x40000000; |
|
|
|
|
|
private const UInt32 GENERIC_READ = 0x80000000; |
|
|
|
|
|
private const UInt32 FILE_SHARE_READ = 0x00000001; |
|
|
|
|
|
private const UInt32 FILE_SHARE_WRITE = 0x00000002; |
|
|
|
|
|
private const UInt32 OPEN_EXISTING = 0x00000003; |
|
|
|
|
|
private const UInt32 FILE_ATTRIBUTE_NORMAL = 0x80; |
|
|
|
|
|
private const UInt32 ERROR_ACCESS_DENIED = 5; |
|
|
|
|
|
|
|
|
|
|
|
private const UInt32 ATTACH_PARRENT = 0xFFFFFFFF; |
|
|
|
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
} |
|
|
} |
|
|
} |