I have a console that is running and I need to get the output. I cannot use startprocess
to start the console as it is spawned separately. I do not have access to the source code, I am simply trying to redirect the output from the console while it is already running.
It turns out that attaching to already running separate process using managed framework is not possible.
However, It is possible to achieve this using Console Api Functions
under kernel32.dll
.
Edit: The code is Improved for better usability
In order to achieve this we need to use FreeConsole
, AttachConsole
, ReadConsoleOutputCharacter
, GetConsoleScreenBufferInfo
and AttachConsole
from WinApi
Declarations of static external libraries:
[DllImport("kernel32.dll")]
private extern static IntPtr GetStdHandle(int nStdHandle);
[DllImport("kernel32.dll")]
static extern bool ReadConsoleOutputCharacter(IntPtr hConsoleOutput,
[Out] StringBuilder lpCharacter, uint nLength, COORD dwReadCoord,
out uint lpNumberOfCharsRead);
[DllImport("kernel32.dll")]
static extern bool FreeConsole();
[DllImport("kernel32.dll")]
static extern bool AttachConsole(int dwProcessId);
[DllImport("kernel32.dll")]
static extern bool GetConsoleScreenBufferInfo(
IntPtr hConsoleOutput,
out CONSOLE_SCREEN_BUFFER_INFO lpConsoleScreenBufferInfo
);
[StructLayout(LayoutKind.Sequential)]
struct COORD
{
public short X;
public short Y;
}
[StructLayout(LayoutKind.Sequential)]
struct CONSOLE_SCREEN_BUFFER_INFO
{
public COORD dwSize;
public COORD dwCursorPosition;
public short wAttributes;
public SMALL_RECT srWindow;
public COORD dwMaximumWindowSize;
}
[StructLayout(LayoutKind.Sequential)]
struct SMALL_RECT
{
public short Left;
public short Top;
public short Right;
public short Bottom;
}
const int STD_OUTPUT_HANDLE = -11;
const Int64 INVALID_HANDLE_VALUE = -1;
We first need to free current console handle because we can only Attach to a single Console
private static string ReadALineOfConsoleOutput(IntPtr stdout, ref short currentPosition)
{
if (stdout.ToInt32() == INVALID_HANDLE_VALUE)
throw new Win32Exception();
//Get Console Info
if (!GetConsoleScreenBufferInfo(stdout, out CONSOLE_SCREEN_BUFFER_INFO outInfo))
throw new Win32Exception();
//Gets Console Output Line Size
short lineSize = outInfo.dwSize.X;
//Calculates Number of Lines to be read
uint numberofLinesToRead = (uint)(outInfo.dwCursorPosition.Y - currentPosition);
if (numberofLinesToRead < 1) return null;
// read from the first character of the first line (0, 0).
COORD dwReadCoord;
dwReadCoord.X = 0;
dwReadCoord.Y = currentPosition;
//total characters to be read
uint nLength = (uint)lineSize * numberofLinesToRead + 2*numberofLinesToRead;
StringBuilder result = new StringBuilder((int)nLength);
StringBuilder lpCharacter = new StringBuilder(lineSize);
for (int i = 0; i < numberofLinesToRead; i++)
{
if (!ReadConsoleOutputCharacter(stdout, lpCharacter, (uint) lineSize, dwReadCoord, out uint lpNumberOfCharsRead))
throw new Win32Exception();
result.AppendLine(lpCharacter.ToString(0, (int)lpNumberOfCharsRead-1));
dwReadCoord.Y++;
}
currentPosition = outInfo.dwCursorPosition.Y;
return result.ToString();
}
public static async Task Main()
{
var processId = 8560;
if (!FreeConsole()) return ;
if (!AttachConsole(processId)) return;
IntPtr stdout = GetStdHandle(STD_OUTPUT_HANDLE);
short currentPosition = 0;
while (true)
{
var r1 = ReadALineOfConsoleOutput(stdout, ref currentPosition);
if (r1 != null)
//write to file or somewhere => //Debug.WriteLine(r1);
}
}
Improvements
ref short currentPosition
added to ReadALineOfConsoleOutput
function for synchronizing currentPosition of the Standard OutputGetConsoleScreenBufferInfo
is used to get lineSize
of the console
short lineSize = outInfo.dwSize.X
is added for lineSizeuint numberofLinesToRead = (uint) (outInfo.dwCursorPosition.Y - currentPosition)
is used to calculate number of lines to be read using difference between actual position of the console and current position of the cursor.lpNumberOfCharsRead
to avoid garbage line endingsIf you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With