Created
September 10, 2017 01:08
-
-
Save drehren/377fc0abe6029f174bbf0193c984cbe3 to your computer and use it in GitHub Desktop.
Reset Console Redirection for VS2017-hosted Windows Application
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Runtime.InteropServices; | |
using Microsoft.Win32.SafeHandles; | |
namespace Utilities | |
{ | |
static class ResetConsoleRedirection | |
{ | |
/// <summary> | |
/// This method will check if the Console Window is opened and redirected. | |
/// You need to call this method BEFORE ANY call to System.Console to avoid setting stuff there. | |
/// </summary> | |
public static void CheckAndReset() | |
{ | |
// If the console has already been allocated, it means that this is a console application and | |
// it doesn't need to be further messed with. | |
if (ConsoleStarted()) | |
{ | |
return; | |
} | |
// Check for ouput redirection | |
if (IsStdHandleRedirected(NativeMethods.StdHandle.Output)) | |
{ | |
Reset(NativeMethods.StdHandle.Output); | |
} | |
// Check for input redirection; normally it isn't | |
if (IsStdHandleRedirected(NativeMethods.StdHandle.Input)) | |
{ | |
Reset(NativeMethods.StdHandle.Input); | |
} | |
} | |
private static void Reset(NativeMethods.StdHandle stdHandle) | |
{ | |
string name = stdHandle == NativeMethods.StdHandle.Input ? "CONIN$" : "CONOUT$"; | |
SafeFileHandle std = NativeMethods.CreateFile(name, | |
NativeMethods.DesiredAccess.GENERIC_READ | |
| NativeMethods.DesiredAccess.GENERIC_WRITE, | |
NativeMethods.ShareMode.FILE_SHARE_READ | |
| NativeMethods.ShareMode.FILE_SHARE_WRITE, | |
IntPtr.Zero, | |
NativeMethods.CreationDisposition.OPEN_EXISTING, | |
0, | |
IntPtr.Zero); | |
NativeMethods.SetStdHandle(stdHandle, std); | |
} | |
/// <summary> | |
/// See https://referencesource.microsoft.com/#mscorlib/system/console.cs,f108bd7fd3c5ebdc | |
/// </summary> | |
/// <param name="stdHandle"> The standard handle to check. </param> | |
/// <returns> True if the handle was redirected, false otherwise. </returns> | |
private static bool IsStdHandleRedirected(NativeMethods.StdHandle stdHandle) | |
{ | |
SafeFileHandle safeIOHandle = NativeMethods.GetStdHandle(stdHandle); | |
NativeMethods.FileType fileType = NativeMethods.GetFileType(safeIOHandle); | |
if ((fileType & NativeMethods.FileType.Char) != NativeMethods.FileType.Char) | |
return true; | |
uint mode; | |
bool success = NativeMethods.GetConsoleMode(safeIOHandle, out mode); | |
return !success; | |
} | |
private static bool ConsoleStarted() | |
{ | |
return !NativeMethods.AllocConsole(); | |
} | |
static class NativeMethods | |
{ | |
[Flags] | |
internal enum DesiredAccess : uint | |
{ | |
NONE = 0x0, | |
GENERIC_READ = 0x80000000, | |
GENERIC_WRITE = 0x40000000, | |
} | |
[Flags] | |
internal enum ShareMode : uint | |
{ | |
NONE = 0x0, | |
FILE_SHARE_READ = 0x00000001, | |
FILE_SHARE_WRITE = 0x00000002, | |
} | |
internal enum CreationDisposition : uint | |
{ | |
OPEN_EXISTING = 3, | |
} | |
internal enum StdHandle | |
{ | |
Input = -10, | |
Output = -11, | |
} | |
[Flags] | |
internal enum FileType : uint | |
{ | |
Char = 0x0002, | |
Disk = 0x0001, | |
Pipe = 0x0003, | |
Remote = 0x8000, | |
Unknown = 0x0000, | |
} | |
[DllImport("kernel32.dll")] | |
internal static extern bool AllocConsole(); | |
[DllImport("kernel32.dll", SetLastError = true, ExactSpelling = true)] | |
internal static extern bool FreeConsole(); | |
[DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)] | |
internal static extern SafeFileHandle CreateFile(string lpFileName, | |
DesiredAccess dwDesiredAccess, | |
ShareMode dwShareMode, | |
IntPtr lpSecurityAttributes, | |
CreationDisposition dwCreationDisposition, | |
UInt32 dwFlagsAndAttributes, | |
IntPtr hTemplateFile); | |
[DllImport("kernel32.dll", SetLastError = true)] | |
internal static extern SafeFileHandle GetStdHandle(StdHandle nStdHandle); | |
[DllImport("kernel32.dll")] | |
internal static extern FileType GetFileType(SafeHandle hFile); | |
[DllImport("kernel32.dll")] | |
internal static extern bool GetConsoleMode(SafeHandle hConsoleHandle, out uint lpMode); | |
[DllImport("kernel32.dll")] | |
internal static extern bool SetStdHandle(StdHandle nStdHandle, SafeHandle hHandle); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment