Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

C# overwriting current line in console not working in conhost.exe

I have a console application that runs a task that reports it’s completion percent as it progresses. While doing this, I display a progress bar to the console. I use Console.SetCursorPosition(0, Console.CursorTop); before calling Console.Write to update the current line so that the progress bar updates in place.

When I run this in Powershell using Windows Terminal it behaves just how I want it to. Each update overwrites the current line. The problem is if I run the application from Powershell in the (legacy) conhost.exe it doesn’t overwrite the line. The output is:

[        ][  0%]
[=       ][  1%]
[=       ][  2%]

… and so on. Here is a complete program that exhibits this behavior:

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

static void Main(string[] args)
{
    Progress<int> progress = new Progress<int>();
    progress.ProgressChanged += Progress_ProgressChanged;

    IProgress<int> reporter = progress;

    for (int i = 0; i < 100; i++)
    {
        Thread.Sleep(1000);
        reporter.Report(i);
    }
}

private static void Progress_ProgressChanged(object? sender, int e)
{
    Console.SetCursorPosition(0, Console.CursorTop);
    Console.Write(GetProgressString(e));
}

private static string GetProgressString(int progress)
{
    // Total width of the progress meter.
    // Console width minus "[][100%]".
    int width = Console.WindowWidth - 8;
    double progressDec = (double)progress / 100;
    int numChars = (int)(progressDec * width);

    StringBuilder meterBuilder = new StringBuilder();

    for (int i = 0; i < numChars; i++)
    {
        meterBuilder.Append('=');
    }

    for (int i = 0; i < (width - numChars); i++)
    {
        meterBuilder.Append(' ');
    }

    return $"[{meterBuilder}][{string.Format("{0, 3}", progress)}%]";
}

Is there a different approach to doing this that will work in the old Windows console host?

>Solution :

Your code overwrites the current line just fine — but in the failing case, "the current line" is not what you think it is.

If you don’t want to advance the row, don’t write to the very last column, because the cursor position has to be after what you wrote, and some terminals will wrap it to the next line proactively.

Alternatively, you could save the value of CursorTop before you write (before the cursor position has a chance to overflow to the next line).

You already are not playing well with any other concurrent console output, because you overwrite whatever is on the current line whether it was generated by the progress bar or not. Saving the Y-coordinate where you actually wrote might improve on that (but you’d also need to restore the cursor position after you update the progress bar, or else other output would repeatedly replace the line after the progress bar instead of properly accumulating).

Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading