0

There's a cmd window.
I want to read the text in it, then, write to it.
The handle of the cmd window is known,
Use C#'s Process is a way, but RedirectStandardOutput won't work.
Because it's running Python and will move the cursor.

I tried to use SendMessage, but it only shows the title of that cmd:
C:\WINDOWS\system32\cmd
But I want it's content text.

Is there a way to read what's showing on a running external console?
(for example, cmd console / python console)

For example:
Hello.exe :

 static void Main(string[] args) { Console.Write("hello world"); Console.CursorLeft -= 5; Console.Write("you \n"); Console.WriteLine("Hello.exe"); Console.ReadLine(); } 

The output would be:

hello you
Hello.exe

Then in test.exe :

 static void Main(string[] args) { if (Process.GetProcesses().Where(x => x.ProcessName.Contains("Hello")).Count() == 0) { Process p = new Process(); p.StartInfo.FileName = "Hello.exe"; p.StartInfo.UseShellExecute = false; p.StartInfo.RedirectStandardOutput = true; p.OutputDataReceived += delegate (object obj, DataReceivedEventArgs drea) { Console.WriteLine(drea.Data); }; p.Start(); p.BeginOutputReadLine(); p.WaitForExit(); } Console.WriteLine("Test.exe"); Console.ReadLine(); } 

The output will be something like:

Unhandled exception. System.ArgumentOutOfRangeException: The value must be greater than or equal to zero and less than the console's buffer size in that dimension. (Parameter 'left') Actual value was -5. at System.Console.SetCursorPosition(Int32 left, Int32 top) at System.Console.set_CursorLeft(Int32 value) at Hello.Program.Main(String[] args)
hello world
Test.exe

Is there any fix for it? -v-

7
  • There's not much you can do to get the functionality you seem to want. The redirected output is a stream, so moving the cursor does not make sense in that context. What you can do to avoid errors is test for Console.IsOutputRedirected and avoid moving the cursor if it is. You'll also notice that when output is redirected, the cursor position remains at (0, 0), even after writing, so moving it to (-5, 0) is going to fail. Commented Nov 13, 2021 at 13:32
  • @sellotape sadly, I cannot change the python file, so the movement of the cursor is a must-have. =( Commented Nov 13, 2021 at 14:15
  • So, is the assertion that the python program crashes if its output is redirected? Or do positioning commands just become ignored in the stream reading .. the next question I have; if your c# program is reading in lines, are you certain the python program outputs lines? Commented Nov 13, 2021 at 20:24
  • 1
    Do you need the progress bar or is there other output you need? Also, curious what happens if you run it in a Command prompt like mypyexe.exe >c:\temp\py.txt - what if anything ends up in the file Commented Nov 13, 2021 at 20:49
  • 1
    That comment didn't answer my question Commented Nov 14, 2021 at 5:05

2 Answers 2

0

I tried to write a simple python script which reproduces this.

 def moveleft(y): print("\033[%dD" %(y), end="") print("Hello World",end="") moveleft(5) print("you ") print("Hello.exe") 

When executing it, the output looks like:

Hello you Hello.exe 

When doing python hello.py > hello.txt, and looking at the hello.txt file, it looks like this:

Hello World<esc>[5Dyou Hello.exe 

Where <esc> is a representation of the Escape character.

When your python script uses the same way as above script to position the cursor, you should not have a problem.

When other means of cursor positioning are used, you are "out of luck". Maybe some help would be Read values already printed to the console, but I do not know how to do that on a remote console.

Sign up to request clarification or add additional context in comments.

1 Comment

Solved! Thanks for your answer, I looked at your related post, then I found stackoverflow.com/questions/12355378
0

It is solved. Much thanks to @Luuk.
I found what I need while looking at the post he gave and related questions!

Check : Read from location on console C#

Use these (by @Glenn Slayden)

[DllImport("kernel32", SetLastError = true)] static extern IntPtr GetStdHandle(int num); [DllImport("kernel32", SetLastError = true, CharSet = CharSet.Ansi)] [return: MarshalAs(UnmanagedType.Bool)] static extern bool ReadConsoleOutputCharacterA( IntPtr hStdout, // result of 'GetStdHandle(-11)' out byte ch, // A̲N̲S̲I̲ character result uint c_in, // (set to '1') uint coord_XY, // screen location to read, X:loword, Y:hiword out uint c_out); // (unwanted, discard) [DllImport("kernel32", SetLastError = true, CharSet = CharSet.Unicode)] [return: MarshalAs(UnmanagedType.Bool)] static extern bool ReadConsoleOutputCharacterW( IntPtr hStdout, // result of 'GetStdHandle(-11)' out Char ch, // U̲n̲i̲c̲o̲d̲e̲ character result uint c_in, // (set to '1') uint coord_XY, // screen location to read, X:loword, Y:hiword out uint c_out); // (unwanted, discard) 

I was able to read a printed char using code:

Example Code Image

Although in this example, only the first char h has been read.
But with this, you will find a way to read all other chars too.
Thus, that's it! Yeah!

OK, but wait, it should be "external console's IO".
Well for this part, the only way I know is that
you could run an independent Console App as the external console app's console.
(Use create Process like what's in the picture in your independent console, or any other better way)

This is a ConsoleReader I made, not pretty, but it works.

class ConsoleReader { [DllImport("kernel32", SetLastError = true)] static extern IntPtr GetStdHandle(int num); [DllImport("kernel32", SetLastError = true, CharSet = CharSet.Ansi)] [return: MarshalAs(UnmanagedType.Bool)] static extern bool ReadConsoleOutputCharacterA( IntPtr hStdout, // result of 'GetStdHandle(-11)' out byte ch, // A̲N̲S̲I̲ character result uint c_in, // (set to '1') uint coord_XY, // screen location to read, X:loword, Y:hiword out uint c_out); // (unwanted, discard) [DllImport("kernel32", SetLastError = true, CharSet = CharSet.Unicode)] [return: MarshalAs(UnmanagedType.Bool)] static extern bool ReadConsoleOutputCharacterW( IntPtr hStdout, // result of 'GetStdHandle(-11)' out char ch, // U̲n̲i̲c̲o̲d̲e̲ character result uint c_in, // (set to '1') uint coord_XY, // screen location to read, X:loword, Y:hiword out uint c_out); // (unwanted, discard) public static readonly IntPtr stdout = GetStdHandle(-11); public static char? ConsoleUnicodeCharAt(uint x, uint y) { uint coord; coord = x; // loword <-- X coord to read coord |= y << 16; // hiword <-- Y coord to read var success = ReadConsoleOutputCharacterW( stdout, out char ch, // U̲n̲i̲c̲o̲d̲e̲ character result 1, // # of chars to read coord, // (X,Y) screen location to read (see above) out _); // result: actual # of chars (unwanted) if (success) { return ch; } return null; } public static char? ConsoleUnicodeCharAt(uint x, uint y,uint read_char_length) { uint coord; coord = x; // loword <-- X coord to read coord |= y << 16; // hiword <-- Y coord to read var success = ReadConsoleOutputCharacterW( stdout, out char ch, // result: single ANSI char read_char_length, // # of chars to read coord, // (X,Y) screen location to read (see above) out uint actual_char_len); // result: actual # of chars (unwanted) if (success) { return ch; } return null; } public static byte? ConsoleAnsiCharAt(uint x, uint y) { uint coord; coord = x; // loword <-- X coord to read coord |= y << 16; // hiword <-- Y coord to read var success = ReadConsoleOutputCharacterA( stdout, out byte ch, // result: single ANSI char 1, // # of chars to read coord, // (X,Y) screen location to read (see above) out _); // result: actual # of chars (unwanted) if (success) { return ch; } return null; } public static string GetLineAt(uint y, Encoding encoding) { uint i = 0; var line_index = y; if (encoding == Encoding.Unicode) { List<char> line_chars = new List<char>(); char? ch; while ((ch = ConsoleUnicodeCharAt(i++, line_index)) != null) { line_chars.Add((char)ch); if (ch == '\0') { break; } } return new string(line_chars.ToArray()); } else if (encoding == Encoding.ASCII) { List<byte> line_bytes = new List<byte>(); byte? b; while ((b = ConsoleAnsiCharAt(i++, line_index)) != null) { line_bytes.Add((byte)b); if (b == byte.MinValue) { break; } } return Encoding.ASCII.GetString(line_bytes.ToArray()); } else { return null; } } public static string GetLineAt_Unicode(uint y, uint trylength) //trylength is for first char { uint i = 0; var line_index = y; List<char> line_chars = new List<char>(); char? ch; while((ch = ConsoleUnicodeCharAt(i++, line_index, trylength) ).HasValue) { line_chars.Add((char)ch); var size = GetCharSize(ch.Value); i += size - 1; if ((char)ch == '\0') { break; } } return new string(line_chars.ToArray()); } public static string GetCurrentLine(Encoding encoding) { return GetLineAt((uint)Console.GetCursorPosition().Top, encoding); } public static string GetCurrentLine_Unicode(uint try_char_length) { return GetLineAt_Unicode((uint)Console.GetCursorPosition().Top, try_char_length); } public static uint GetCharSize(char c) { var b = BitConverter.GetBytes(c); uint size = (uint)b.Length; for (int i=b.Length-1;i>=0;i--) { if (b[i] != 0) { break; } size--; } return size; } } 

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.