views:

726

answers:

4

I am writing a C# console application that connects to a server trough TCP, it uses a separate thread to listen for incoming messages from the server and I want it to write them to the console while at the same time reading a message from the console. I was able to do that, but I have a problem.

The console displays this while I type and a messages comes in:

msg from server
msg from server
my msmsg from server
g to server

And i want it to separate my message from the servers mesages like so:

msg from server
msg from server
msg from server
my msg to server

If I receive a message I still want to keep my typed message, but I don't want it to mix up with the received message, I want it to remain complete on the last line.

Can I do that? And how?

Can I shift my message to the end of the console, when a message from the server comes in?

+1  A: 

You can't do this directly via the BCL in C#. There are two main alternatives, though.

1) Turn this into a GUI app, and have separate input/output areas. This is the most "clear" option from a user's POV, but requires a GUI app instead of a console app.

2) P/Invoke into the console API directly. This gives you complete control of the console's view, point by point. See SetConsoleCursorPosition and WriteConsole, etc.

Reed Copsey
+1 for the P/Invoke.
John
What does that offer than this doesn't? http://msdn.microsoft.com/en-us/library/system.console_members(VS.80).aspx
Rodrigo Queiro
Thank you very much, I will try the Console API aproach
Christian Toma
The Console class may work, since you can probably do what you want with MoveBufferArea and some bookkeeping. The console class doesn't provide all of teh control of the native api, though, especially some of the buffer manipulation functions.
Reed Copsey
+1  A: 

You need to use a lock on some object to stop both threads using the console at the same time. Declare something like this:

public static class ThreadSafeConsole
{
    private static object _lockObject = new object();

    public static void WriteLine(string str)
    {
        lock (_lockObject) 
        {
            Console.WriteLine(str);
        }
    }
}

Now call ThreadSafeConsole.WriteLine instead of Console.WriteLine.

Daniel Earwicker
You misunderstood me, I am trying to read while the listening thread can write whenever a message comes. If I take your approach I can't read and write to the console at the same time. Thanks
Christian Toma
Then your question is incomprehensible! :) Either you need to synchronize access to a single console, or you should write a GUI instead of a console app.
Daniel Earwicker
I need it to be a console app. Sorry for the incomprehensible questions, but others seem to have understood it just fine. Thanks
Christian Toma
But by the time you have taken detailed control of the cursor position, then you haven't written a console app; you've re-implemented what can be done far more easily with a GUI. The only real point of a console app over a GUI is to have simple I/O streams for piping to/from other commands or files.
Daniel Earwicker
It needs to be a console app, I use SSH to connect to the PC's console. :|
Christian Toma
Did you know you can use Remote Desktop over SSH?
Daniel Earwicker
I know, but I am limited to command line SSH.
Christian Toma
+1  A: 

I believe this is in fact possible with the standard .NET Console API, using a bit of hackery. What you need to do is create an asynchronous Read/ReadLine method (which I assume you have already done, judging by your post) and allow it to be cancelled as soon as new data arrives. I'm going to assume you're sending input line by line for now. The pseudocode for the "new data handler" might be something like this:

Save the current input buffer.
Cancel the current asynchronous read.
Reset the cursor position to the end of the last writing of new data.
Output the new data.
Save the cursor position.
Restart the asynchronous read event.

In particular, you'll need to mess around with Console.CursorLeft and Console.CursorTop properties. You might be able to avoid some of the hackery by interfacing with the Win32 API console functions directly, but it's possibly not worth the bother.

Hope that helps.

Noldorin
I thought of this, but I also thought that a simpler approach exists. If I won't find anything else, this is what I'll use, thank you very much.
Christian Toma
@Toma: No problem... And yYeah, I'm afraid you're not going to get anything simpler. I actually investigated this same thing a while back, and the clear conclusion was that there was no straightforward method.
Noldorin
Let me know if you're not clear on any of the implementation details. This method should basically work whether you want to read/write each char at a time, or only whole lines (sending data upon reading the Enter key).
Noldorin
A: 

If I understand you correctly, you'd have to define what the beginning and ending of 'typing to console' is for your application so that you can still lock on an object while that is happening, and not inserting messages from your listener thread into your typed text.

public static Object consoleLock = new Object();
public static void Main(string[] args)
{
    lock (consoleLock)
    {
        // now nothing can write to the console (if it's trying to lock onto it)
        Console.WriteLine("Please Input Something");
        // read from console
    }
    // now, your separate thread CAN write to the console - without 
    // interrupting your input process
}
SnOrfus
Hey sorry for the confusion, I edited my question.If I receive a message I still want to keep my typed message, but I don't want it to mix up with the received message, I want it to remain complete on the last line.
Christian Toma