none
Console.ReadLine() not working with .net Framework > 3.5 RRS feed

  • Question

  • Hi all,

    I am launching a slave C# process from a master C++ software, and communicating between them using the standard input an output channels.

    The following code works fine when compiled with  .net Framework 3.5 :

    namespace ConsoleApplication1
    {
        class Program
        {
            static void Main(string[] args)
            {
                string text;
                while (true)
                {
                    Console.WriteLine("0");
                    text = Console.ReadLine();               
                    Console.WriteLine("1");
                    Console.WriteLine(text);
                }
            }
        }
    }

    When compiling with the .net Framework 4.0 and 4.5, Console.ReadLine() never returns. (But Console.WriteLine("0") does still work).

    Thanks for any help you can give.





    Wednesday, April 29, 2015 5:04 PM

Answers

  • There is indeed a change that was introduced in .NET 4, when reading from a console stream it first tries to wait on the stdout handle before actually reading from it:

    http://referencesource.microsoft.com/#mscorlib/system/io/__consolestream.cs,190

    That's a bit odd as this appears to end up calling WaitForMultipleObjects on a pipe handle and such handles aren't specifically supported by Win32's wait functions. This usually works but somehow this fails in the case of QT which probably has its own weirdness (using IO completion ports to read from the process's output, sort of overkill).

    Consider opening a bug report on Connect to see what MS has to say about this.

    As a workaround consider using Win32 functions directly to start the process - CreatePipe, CreateProcess... I tried that and it seems to work fine.


    Saturday, May 2, 2015 10:25 AM
    Moderator

All replies

  • what about Console.WriteLine("1")  is it working? I mean when you execute the above code

    Fouad Roumieh


    Wednesday, April 29, 2015 5:29 PM
  • Console.WriteLine("1") is never reached.

    If the parent program sends "ping\n", the resulting communication is as follows :

    Using .net Framework 3.5 :

    Receiving message : "0
    "
    Sending message :  "ping
    "
    Receiving message : "1
    "
    Receiving message : "ping
    0
    "

    Using .net Framework 4.5 :

    Receiving message : "0
    "
    Sending message :  "ping
    "

    Wednesday, April 29, 2015 5:42 PM
  • it could be an issue with the text that you passing to ReadLine() that is causing it to break. Try to pass simple text to test like abc, and also put a try catch to catch the exception that is happening.

    Fouad Roumieh

    Wednesday, April 29, 2015 5:52 PM
  • I mean:

     string text;
                while (true)
                {
                    try
                    {
                        Console.WriteLine("0");
                        text = Console.ReadLine();
                        Console.WriteLine("1");
                        Console.WriteLine(text);
                    }
                    catch (Exception ex)
                    {
                        Console.WriteLine(ex.Message);
                    }
                   
                }


    Fouad Roumieh

    Wednesday, April 29, 2015 5:55 PM
  • Thank you for your help.

    The behaviour is the same as previously.

    Is Console.ReadLine() expecting something more than a "\n" to validate the reading ?


    Wednesday, April 29, 2015 6:04 PM
  • Thank you for your help.

    The behaviour is the same as previously.

    Is Console.ReadLine() expecting something more than a "\n" to validate the reading ?


    It is expecting you to press the ENTER key on the keyboard for it to continue which is usually \r\n but could depend on the O/S. See value in variable System.Environment.NewLine

    EDIT

    Also check out the documentation here LINK. It seems there are some other dependencies like the maximum length for the input buffer (256).


    Mark as answer or vote as helpful if you find it useful | Igor


    • Edited by IWolbers Wednesday, April 29, 2015 6:16 PM
    Wednesday, April 29, 2015 6:13 PM
  • I'm a little confused, but what you are asking.  Are you trying to use Console.ReadLine to read what you just posted as Console.WriteLine?

    Your program is executing just how it is written

    Console.WriteLine("0") // output 0

    Console.ReadLine() // Waits for user input, it doesn't read what was just output.

    // Never finishes executing.

    • Proposed as answer by KyleS Wednesday, April 29, 2015 6:50 PM
    • Unproposed as answer by SimpleIsBetter Wednesday, April 29, 2015 7:11 PM
    Wednesday, April 29, 2015 6:50 PM
  • Are you testing this directly in VS? or you communicating to the console app via C++ app? 

    Fouad Roumieh

    Wednesday, April 29, 2015 6:55 PM
  • I am communicating with the console app via a master C++ app coded wih Qt.

    The master app sends a string "ping\r\n" to the console app, which sends back the string received with Console.WriteLine(text).
    Wednesday, April 29, 2015 7:10 PM
  • There are so many ways to facilitate inter-program communication. May I ask what the reason is to do this or is it just wanting to see if it would work?

    Also did you check out the Environment.NewLine I mentioned earlier?


    Mark as answer or vote as helpful if you find it useful | Igor

    Wednesday, April 29, 2015 7:25 PM
  • I checked what was in the Environment.NewLine using this code :

    namespace ConsoleApplication1
    {
        class Program
        {
            static void Main(string[] args)
            {
                char[] textCharArray = Environment.NewLine.ToCharArray();
                foreach (char c in textCharArray)
                {
                    Console.WriteLine((int)c);
                }
            }
        }
    }
    and it outputs \r\n with both .net Framework 3.5 and 4.5, so no difference here.



    Wednesday, April 29, 2015 7:26 PM
  • I am communicating with the console app via a master C++ app coded wih Qt.

    The master app sends a string "ping\r\n" to the console app, which sends back the string received with Console.WriteLine(text).

    I don't know how C++ apps executes but is it possible to get a dummy sample of this C++ app to run on windows machine to be able to reproduce this issue?

    Fouad Roumieh

    Wednesday, April 29, 2015 7:32 PM
  • I am trying to use the standard channels to communicate because the Qt object QProcess offers them for communication, meaning I do not need to implement anything for communication.

    Also, I implemented an inter-program communication Using Data Copy, but since I only have to send a simple doWork order to the child process once in a while, it brings complexity I don't need in my program.
    Wednesday, April 29, 2015 7:47 PM
  • Here is a dummy sample code for the master app:
    It uses the Qt framework, and is a Qt console application.
    Type ping in the console, and the C# app should answer ping back.

    #include <QCoreApplication>
    #include <QProcess>
    #include <iostream>
    #include <string>
    using namespace std;
    
    int main(int argc, char *argv[])
    {
        QCoreApplication a(argc, argv);
    
        // Path to the C# executable
        QString program = "D:/Documents/ConsoleApplication1/ConsoleApplication1/bin/Release/ConsoleApplication1.exe";
    
        // Start child Process
        QProcess * process = new QProcess();
           process->setProgram(program);
           // Execute lambda function whenever a message from the process is received
           QObject::connect(process, &QProcess::readyReadStandardOutput, [&](){ cout << process->readAll().toStdString(); } );
           process->start();
    
        string text;
        cin >> text;
        process->write( QByteArray::fromStdString(text) + "\r\n" );
    
        return a.exec();
    }





    Wednesday, April 29, 2015 7:52 PM
  • So I was tinkering with the code, and found out that if I add a sleep period at the beginning of the program, Console.ReadLine() actually reads the data sent during this sleep period, send it back to the master app, and then stops reading again :

    namespace ConsoleApplication1
    {
        class Program
        {
            static void Main(string[] args)
            {
                string text;
                System.Threading.Thread.Sleep(3000);
                while (true)
                {
                    //Console.WriteLine("0");    // Tested with and without, no impact
                    text = Console.ReadLine();
                    Console.WriteLine("1");
                    Console.WriteLine(text);
                }
            }
        }
    }

    Display on the master software is as follows :

    Sending message :  "earlyPing
    "
    Receiving message :  "1
    "
    Receiving message :  "earlyPing
    "
    Sending message :  "ping
    "
    So it may be a clue for a .net expert



    Wednesday, April 29, 2015 11:30 PM
  • Here is a dummy sample code for the master app:
    It uses the Qt framework, and is a Qt console application.
    Type ping in the console, and the C# app should answer ping back.

    #include <QCoreApplication>
    #include <QProcess>
    #include <iostream>
    #include <string>
    using namespace std;
    
    int main(int argc, char *argv[])
    {
        QCoreApplication a(argc, argv);
    
        // Path to the C# executable
        QString program = "D:/Documents/ConsoleApplication1/ConsoleApplication1/bin/Release/ConsoleApplication1.exe";
    
        // Start child Process
        QProcess * process = new QProcess();
           process->setProgram(program);
           // Execute lambda function whenever a message from the process is received
           QObject::connect(process, &QProcess::readyReadStandardOutput, [&](){ cout << process->readAll().toStdString(); } );
           process->start();
    
        string text;
        cin >> text;
        process->write( QByteArray::fromStdString(text) + "\r\n" );
    
        return a.exec();
    }





    @SimplelsBetter,

    Per my understanding, Console.ReadLine() haven't change in .NET farmework >3.5. I am curious about how they communicate between them.

    After consult with my colleague, about Qt framework is a third-party product.

    Please also submit a question in QT forum.

    http://www.qtcentre.org/forum.php?s=dd5a5076eb28a8b5d1138f36344a9538

    Thanks for your understanding.

    Best regards,

    Kristin


    We are trying to better understand customer views on social support experience, so your participation in this interview project would be greatly appreciated if you have time. Thanks for helping make community forums a great place.
    Click HERE to participate the survey.


    Thursday, April 30, 2015 9:52 AM
    Moderator
  • I've create a dummy communication between two processes, I cannot simulate your case due to the QT dependency. The ReadLine is worked as expected, the Threading that you applied maybe is showing a sync issue between the sender and the receiver but I'm not sure of that, it needs more investigation. Did you try to apply the Sleep inside the loop but will less than 3 second maybe 2ms=200?

    The code that I worked on:

    Sender:

    static void Main(string[] args)
            {
                Process myProcess = new Process();
    
                myProcess.StartInfo.FileName = @"MypathtoReceiver\ReadLineReceiver.exe";
                myProcess.StartInfo.UseShellExecute = false;
                myProcess.StartInfo.RedirectStandardInput = true;
    
                myProcess.Start();
    
                StreamWriter myStreamWriter = myProcess.StandardInput;
    
                // Prompt the user for input text lines to sort. 
                // Write each line to the StandardInput stream of
                // the sort command.
                String inputText;
                int numLines = 0;
                do
                {
                    inputText = Console.ReadLine();
                    if (inputText.Length > 0)
                    {
                        numLines++;
                        myStreamWriter.WriteLine(inputText);
                    }
                } while (inputText.Length != 0);
            }

    Receiver:

    static void Main(string[] args)
            {
                string text;
                System.Threading.Thread.Sleep(3000);
                while (true)
                {
                    Console.WriteLine("Waiting for input...");
                    text = Console.ReadLine();
                    Console.WriteLine("Received Successfully: " + text);
                    Console.WriteLine("Sending Back: " + text);
                }
            }

    Result:


    Fouad Roumieh

    Thursday, April 30, 2015 7:23 PM
  • @ Fouad Roumieh,

    I tried with sleep periods of 1000ms and 2000ms, it didn't change the application behaviour.

    If I put the sleep period inside the loop right before the Console.ReadLine(), every input receive before the 3 seconds sleep is sent back to the master app, and then the program stops communicating.

    If I put the sleep period right after the Console.ReadLine(), no data is ever sent back to the master app.

    I tested the communication between 2 .net app with your code, and it is working fine on my computer too.

    Thursday, April 30, 2015 9:19 PM
  • @Kristin,

    I posted the same question on the Qt Centre forum.

    Thursday, April 30, 2015 9:25 PM
  • @ Fouad Roumieh,

    I tried with sleep periods of 1000ms and 2000ms, it didn't change the application behaviour.

    If I put the sleep period inside the loop right before the Console.ReadLine(), every input receive before the 3 seconds sleep is sent back to the master app, and then the program stops communicating.

    If I put the sleep period right after the Console.ReadLine(), no data is ever sent back to the master app.

    I tested the communication between 2 .net app with your code, and it is working fine on my computer too.

    I'm seeing that your code in C++ is very similar to what I did in .net: starting a process and passing comnads to ...what is the reason for choosing QT for this?

    Fouad Roumieh

    Friday, May 1, 2015 5:22 AM
  • The caller program is coded in C++ and uses the Qt framework, and is too big to be ported to .net.
    Friday, May 1, 2015 5:51 PM
  • There is indeed a change that was introduced in .NET 4, when reading from a console stream it first tries to wait on the stdout handle before actually reading from it:

    http://referencesource.microsoft.com/#mscorlib/system/io/__consolestream.cs,190

    That's a bit odd as this appears to end up calling WaitForMultipleObjects on a pipe handle and such handles aren't specifically supported by Win32's wait functions. This usually works but somehow this fails in the case of QT which probably has its own weirdness (using IO completion ports to read from the process's output, sort of overkill).

    Consider opening a bug report on Connect to see what MS has to say about this.

    As a workaround consider using Win32 functions directly to start the process - CreatePipe, CreateProcess... I tried that and it seems to work fine.


    Saturday, May 2, 2015 10:25 AM
    Moderator