Writing to handle 3...? (Accessing cmd.exe handles 1,2,3... programmatically)
Posted: 18 Jul 2020 08:31
I tried to write handle 3 with following. There is no way to write directly to handle 3 so i create a file to with the hope of writing to handle 3 but it does not work!
It works fine for handle 1 and handle 2.
It works fine for handle 1 and handle 2.
Code: Select all
using Microsoft.Win32.SafeHandles;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
namespace MyStdHandles
{
class Program
{
[DllImport("kernel32.dll",
EntryPoint = "GetStdHandle",
SetLastError = true,
CharSet = CharSet.Auto,
CallingConvention = CallingConvention.StdCall)]
private static extern IntPtr GetStdHandle(int nStdHandle);
private const int STD_INPUT_HANDLE = -10;
private const int STD_OUTPUT_HANDLE = -11;
private const int STD_ERROR_HANDLE = -12;
private const int STD_HANDLE3 = -13;
[DllImport("kernel32.dll", CharSet = CharSet.Auto)] //, 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
);
const UInt32 GENERIC_WRITE = 0x40000000;
const UInt32 GENERIC_READ = 0x80000000;
const UInt32 OPEN_EXISTING = 0x00000003;
const int FILE_SHARE_WRITE = 2;
[DllImport("kernel32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool SetStdHandle(int nStdHandle, IntPtr hHandle);
[DllImport("kernel32.dll", SetLastError = true)]
static extern bool GetConsoleMode(IntPtr hConsoleHandle, out uint lpMode);
[DllImport("kernel32.dll", SetLastError = true)]
static extern bool SetConsoleMode(IntPtr hConsoleHandle, uint dwMode);
public const uint CREATE_NEW = 1;
static void WriteNewHandle(string message)
{
var outFile = CreateFileW("CONOUT$", GENERIC_WRITE | GENERIC_READ, FILE_SHARE_WRITE, IntPtr.Zero, OPEN_EXISTING, /*FILE_ATTRIBUTE_NORMAL*/0, IntPtr.Zero);
var safeHandle = new SafeFileHandle(outFile, true);
SetStdHandle(STD_OUTPUT_HANDLE, outFile);
var fs = new FileStream(safeHandle, FileAccess.Write);
var writer = new StreamWriter(fs) { AutoFlush = true };
Console.SetOut(writer);
writer.WriteLine(message);
writer.Flush();
}
static int GetHandle(string handle)
{
int stdHandle = STD_OUTPUT_HANDLE;
switch (handle)
{
//case "1": stdHandle = STD_OUTPUT_HANDLE; break;
case "2": stdHandle = STD_ERROR_HANDLE; break;
case "3": stdHandle = STD_HANDLE3; break; // It does not work
}
return stdHandle;
}
static void WriteHandle(string handle, string message)
{
if (handle.Trim() == "3")
{
WriteNewHandle(message);
return;
}
IntPtr stdHandle = GetStdHandle(GetHandle(handle));
SafeFileHandle safeFileHandle = new SafeFileHandle(stdHandle, true);
FileStream fileStream = new FileStream(safeFileHandle, FileAccess.Write);
Encoding encoding = Encoding.ASCII;
StreamWriter writer = new StreamWriter(fileStream, encoding);
writer.WriteLine(message);
writer.Flush();
}
static void Main(string[] args)
{
// https://stackoverflow.com/questions/5711291/get-the-handle-and-write-to-the-console-that-launched-our-process
if (args.Length < 2)
{
Console.WriteLine("[arg1: Handle Number] [arg2: message1] [arg3: Handle Number] [arg4: message2]\n");
Console.WriteLine("Test with this;\n MyStdHandles.exe 1 normal 2 error 2>&1 | findstr /A:4E /N \"^\"");
return;
}
WriteHandle(args[0], args[1]);
if (args.Length >= 4)
{
WriteHandle(args[2], args[3]);
}
}
}
}