I have a simple console app that writes out status of various resources in a nicely formatted way.
This app is using some 3rd party components to connect to places.
Those components unfortunately do a lot Console.Writes (or some sort of logging) which all ends up intertwined with my messages.
I tried redirecting Console output (in hopes that i could filter non-mine messages), but that seems to work ONLY on my messages.
var sb = new StringBuilder();
TextWriter tw = new StringWriter(sb);
Console.SetOut(tw);
So this works in redirecting console writes, but only on the ones i did.. output from 3rd party components is still streaming to my screen.. any other ways to supress that?
The reason you're not able to redirect the output of the third party components is because you're calling redirect on your process, not theirs. To do this, loop over the processes, find the ones that are writing to the console and redirect their output.
using System.Diagnostics;
Process[] processlist = Process.GetProcesses();
foreach(Process theprocess in processlist){
// you'll actually need to use something like the process name or id here.
if (theprocess == MyThirdPartyComponentsProcess)
{
theprocess.StartInfo.UseShellExecute = false;
theprocess.StartInfo.RedirectStandardOutput = true;
}
}
You'll have to be running as administrator for this work.
I've thought of one fairly hacky way:
Capture the existing Console.Out so you can reuse it in your "real" writer
Create your own TextWriter implementation, which...
... when it's asked to write, checks whether the calling code is in your assembly. See Assembly.GetCallingAssembly
So long as you don't have inlining problems, you should be able to check the context, and drop any output you don't want. You'd probably have to call Console.Out.WriteLine directly instead of Console.WriteLine, mind you - otherwise the caller will be the Console class.
A better solution would be to change your code to use log4net or something similar, so you could get your output in a more configurable way, not on the console - assuming your own use is also logging. (If it's for interactive output, something like the above may be the only way...)
Since, there doesn't seem to be a reasonable quick way to suppress these, I went with plan B, that is deferring my messages to the end. This way all the logging gets through, and than i write out all the information i am interested in.
I broke it down into Success/Warn/Error methods
public static void WriteError(string message, params string[] args) {
writerTasks.Add(() => {
var c = Console.ForegroundColor;
Console.ForegroundColor = ConsoleColor.Red;
Console.WriteLine(message, args);
Console.ForegroundColor = c;
});
}
and at the end of the execution, i call this method to flush it out.
private static void WriteResults() {
foreach (var t in writerTasks)
t();
}
i do it this way, because i am changing text color depending on message type, which is contained within each action.
in my case this works great, since the information scrolls up hiding all the logging.. which in fact is also beneficial.. just didn't want it dispersed between the main output
Related
I have a third party DOS process which writes data about its progress to the command line.
I want to react on the progress. Normally I would use a Process with RedirectStandardOutput = true and RedirectStandardError = true and then
.OutputDataReceived +=xyzOutputDataReceived;
.ErrorDataReceived += xyzErrorDataReceived;
.Start();
.BeginOutputReadLine();
.BeginErrorReadLine();
Normally this works. and I got what i need as DataReceivedEventArg.
In this case the process seems to update the same line it has written (how is that possible?), so it writes 15 %, 15% changes to 18% and so on. Only at the end of execution it seems that the data is flushed to StandardOutput.
Also if i just try to pipe data to a text file (eg odb.exe >> output.txt) it shows nothing.
Is there any way to get the temporary data?
The question is not about getting the Standard Output, this works fine (synchronously and asynchronously). It is about how to get output from a process which I cannot change, and which does not seem to flush it's output to the standard stream.
Like juharr says, you need to use Win32 to screen scrape the console.
Fortunately you don't need to write that code yourself. You can use the buffer-reader from this post: https://stackoverflow.com/a/12366307/5581231
The BufferReader reads from standardout. I suppose you are writing a wpf or winforms application so we'll also have to get a reference to the console window of the DOS application. For this, we will use the Win32 API call AttachConsole.
[System.Runtime.InteropServices.DllImport("kernel32.dll")]
private static extern bool AttachConsole(int pid);
I wrote a small example program that demonstrates the usage. It starts the exe and attaches to its console. It then scrapes the entire window once a second, and dumps the output to the debugger output window. You should be able to modify this to search the console content for any keywords etc. that you can use to track the progress of the program. Or you could dump it to a textfield or something in your UI, possibly after comparing it for changes?
var process = Process.Start(#"..path to your exe....");
//Wait for the DOS exe to start, and create its console window
while (process.MainWindowHandle == IntPtr.Zero)
{
Thread.Sleep(500);
}
//Attach to the console of our DOS exe
if (!AttachConsole(process.Id))
throw new Exception("Couldn't attach to console");
while (true)
{
var strings = ConsoleReader.ReadFromBuffer(0, 0,
(short)Console.BufferWidth,
short)Console.BufferHeight);
foreach (var str in strings.
Select(s => s?.Trim()).
Where(s => !String.IsNullOrEmpty(s)))
{
Debug.WriteLine(str);
}
Thread.Sleep(1000);
}
Good Luck!
What I want to have happen is that the console window just goes away, or better yet that it is hidden, but I want my application to keep running. Is that possible? I want to be able to use Console.WriteLine and have the console serve as an output window. I want to be able to hide and show it, and I don't want the whole app to die just because the console was closed.
EDIT
Code:
internal class SomeClass {
[DllImport("kernel32")]
private static extern bool AllocConsole();
private static void Main() {
AllocConsole();
while(true) continue;
}
}
EDIT 2
I tried the accepted solution here [ Capture console exit C# ], per the suggestion in the comments on this question. The example code is bugged in that the DLLImport needs to be "kernel32.dll" or "kernel32", not "Kernel32". After making that change, I'm getting a message to my handler for CTRL_CLOSE_EVENT when I click the X on the console window. However, calling FreeConsole and/or returning true doesn't prevent the application from terminating.
Ah, yes, this is one of the caveats of using the Windows console subsystem. When the user closes the console window (regardless of how the console was allocated), all of the processes that are attached to the console are terminated. That behavior makes obvious sense for console applications (i.e., those that specifically target the console subsystem, as opposed to standard Windows applications), but it can be a major pain in cases like yours.
The only workaround that I know of is to use the SetConsoleCtrlHandler function, which allows you to register a handler function for Ctrl+C and Ctrl+Break signals, as well as system events like the user closing the console window, the user logging off, or the system shutting down. The documentation says that if you're only interested in ignoring these events, you can pass null for the first argument. For example:
[DllImport("kernel32")]
static extern bool SetConsoleCtrlHandler(HandlerRoutine HandlerRoutine, bool Add);
delegate bool HandlerRoutine(uint dwControlType);
static void Main()
{
AllocConsole();
SetConsoleCtrlHandler(null, true);
while (true) continue;
}
That works perfectly for Ctrl+C and Ctrl+Break signals (which would have otherwise caused your application to terminate as well), but it doesn't work for the one you're asking about, which is the CTRL_CLOSE_EVENT, generated by the system when the user closes the console window.
Honestly, I don't know how to prevent that. Even the sample in the SDK doesn't actually allow you to ignore the CTRL_CLOSE_EVENT. I tried it in a little test app, and it beeps when you close the window and prints the message, but the process still gets terminated.
Perhaps more worryingly, the documentation makes me think it is not possible to prevent this:
The system generates CTRL_CLOSE_EVENT, CTRL_LOGOFF_EVENT, and CTRL_SHUTDOWN_EVENT signals when the user closes the console, logs off, or shuts down the system so that the process has an opportunity to clean up before termination. Console functions, or any C run-time functions that call console functions, may not work reliably during processing of any of the three signals mentioned previously. The reason is that some or all of the internal console cleanup routines may have been called before executing the process signal handler.
It's that last sentence that catches my eye. If the console subsystem starts cleaning up after itself immediately in response to the user attempting to close the window, it may not be possible to halt it after the fact.
(At least now you understand the problem. Maybe someone else can come along with a solution!)
Unfortunately there's nothing you can do to really alter this behaviour.
Console windows are "special" in that they're hosted by another process and do not allow sub-classing. This limits your ability to modify their behaviour.
From what I know, your two options are:
1. Disable the close button altogether. You can do this with the following code fragment:
HWND hwnd = ::GetConsoleWindow();
if (hwnd != NULL)
{
HMENU hMenu = ::GetSystemMenu(hwnd, FALSE);
if (hMenu != NULL) DeleteMenu(hMenu, SC_CLOSE, MF_BYCOMMAND);
}
2. Stop using consoles altogether, and implement your own text output solution.
Option #2 is the more complicated option but would provide you the greatest control. I found an article on CodeProject that implements a console-like application using a rich edit control to display the text (rich edit controls have the ability to stream text like the console, so they are well suited to this sort of application).
On closing the console window obtained using AllocConsole or AttachConsole, the associated process will exit. There is no escape from that.
Prior to Windows Vista, closing the console window would present a confirmation dialogue to the user asking him whether the process should be terminated or not but Windows Vista and later do not provide any such dialogue and the process gets terminated.
One possible solution to work around this is avoiding AttachConsole altogether and achieving the desired functionality through other means.
For instance in the case described by OP, console window was needed to output some text on Console using Console static class.
This can be achieved very easily using inter-process communication. For example a console application can be developed to act as an echo server
namespace EchoServer
{
public class PipeServer
{
public static void Main()
{
var pipeServer = new NamedPipeServerStream(#"Com.MyDomain.EchoServer.PipeServer", PipeDirection.In);
pipeServer.WaitForConnection();
StreamReader reader = new StreamReader(pipeServer);
try
{
int i = 0;
while (i >= 0)
{
i = reader.Read();
if (i >= 0)
{
Console.Write(Convert.ToChar(i));
}
}
}
catch (IOException)
{
//error handling code here
}
finally
{
pipeServer.Close();
}
}
}
}
and then instead of allocating/attaching a console to the current application, the echo server can be started from within the application and Console's output stream can be redirected to write to the pipe server.
class Program
{
private static NamedPipeClientStream _pipeClient;
static void Main(string[] args)
{
//Current application is a Win32 application without any console window
var processStartInfo = new ProcessStartInfo("echoserver.exe");
Process serverProcess = new Process {StartInfo = processStartInfo};
serverProcess.Start();
_pipeClient = new NamedPipeClientStream(".", #"Com.MyDomain.EchoServer.PipeServer", PipeDirection.Out, PipeOptions.None);
_pipeClient.Connect();
StreamWriter writer = new StreamWriter(_pipeClient) {AutoFlush = true};
Console.SetOut(writer);
Console.WriteLine("Testing");
//Do rest of the work.
//Also detect that the server has terminated (serverProcess.HasExited) and then close the _pipeClient
//Also remember to terminate the server process when current process exits, serverProcess.Kill();
while (true)
continue;
}
}
This is just one of the possible solutions. In essence the work around is to allot the console window to its own process so that it can terminate without affecting the parent process.
You can do this by disabling keyboard mouse input by external program called Keyfreez.
you can use it multiple times in your program where no user input required. And if any user input require u can add a process Takskkill /f /IM .
https://www.sordum.org/7921/bluelife-keyfreeze-v1-4-block-keyboard-and-mouse/
Hope this helps all of you
I have a WPF application that can take a few optional command line arguments.
This application is also a single instance application (using a mutex to close any instances if one is already open).
What I want for it to do though, is if something tries to open the application with some cmd line args, that the application will do what it's suppose to do with those (in my application it opens different dialogs based on the cmd line).
What is the easiest way to achieve this?
In psedo code here is what i'm looking for
protected override void OnStartup(StartupEventArgs e)
{
bool mutexIsNew;
using (System.Threading.Mutex m =
new System.Threading.Mutex(true, "MyApplication", out mutexIsNew))
{
//if this is not the first instance of the app
if (!mutexIsNew)
{
//if there is some cmd line args
if (e.Args.Length > 0)
{
//send the args to the older instance so it can handle them
SendToOtherInstance(e.Args);
//shutdown this new instance
Application.Current.Shutdown();
}
}
}
base.OnStartup(e);
}
There are lots of implementations of single instance apps on Code Project, actually there are so many of them it's hard to decide which one you want...
I tried several solutions, and I really like this one. It makes it very easy to intercept command line parameters passed to the second instance.
Why don't you just send a Windows message in the WM_USER range. You'll need to do a bit of marshalling of the information but you can do that with GlobalAlloc, GlobalLock, etc. quite easily.
You may wish to consider reversing the logic, ie. close the already running instance and re-launch with your new parameters.
If you're using .net 4, you might consider memory mapped files for inter-process communication. The second instance could write some data to shared memory, set a system mutex to notify the original instance, then shut-down. See this overview of memory mapped files.
Or, simpler yet, write the command line arguments to a simple text file in a folder that is always monitored by the original instance. The original instances sees the new file, processes it, then deletes it. This approach works with any version of .net and would be easier to test/debug.
I'd like for a single console application to spawn other console windows and output to different ones at different times inside of a C# console application. Preferably within one console application, I spawn some other consoles, write to them, and close them during the finally block of the original console application.
What's the ideal way to do this in C#?
I don't believe you can do this with a regular console application. The closest you could come would be to create a your own form in WinForms/WPF which behaved in roughly the same was as a normal console window.
I suppose you could spawn extra processes which each had their own console, and write to them via network connections or named pipes etc... it would be pretty ugly though.
You can do this with Auto/Manual EventWaitHandles in C# combined with countless other techniques. However, you should probably step back and see what you are trying to accomplish and see if a winform app would be a better fit. Maybe post more details and ask for ideas.
A single process can only ever have one true Standard In, Error and Out.
You can fake different ones, especially in .Net because after all they are presented as managed streams which would be fine at the push/pull and of the pipe. The problem is the output/input end i.e. the bit you might be piping to a file, or where you are requesting user input. These simply won't play ball since the OS supplies no multiplexing method itself.
Using simple means at best you could do something that sent output to multiple different windows which looked much like a console window.
With much complexity you would handle reading from them too. In essence you are writing a window which pretends to be a console, and getting it reasonably close to all the little intricacies of console windows is (increasingly) hard.
It would be simple to have (say) a fake console per thread by creating a class like so. I only bother with Out, In and Err follow easily from this.
public class MultiplexByThreadConsole : IDisposable
{
private readonly TextWriter originalOut;
private readonly TextWriter myOut = new IndividualMultiplex();
public MultiplexByThreadConsole()
{
this.originalOut = Console.Out;
Console.SetOut(this.myOut);
}
public void Dispose()
{
Console.SetOut(this.originalOut);
}
private class IndividualMultiplex : TextWriter
{
[ThreadStatic]
private readonly TextWriter actual;
// override all the required functions and any
// others you want to wrap
public override void Write(char c)
{
if (actual == null)
{
actual = MakeWhateverYouReallyWantToOutputTo();
}
actual.Write(c);
}
}
}
Then somewhere in Main (or wherever) do:
using(new MultiplexByThreadConsole())
{
// off you go all threads during this get their own faked console.
}
You would likely keep the In/Out/Err all pointing to some common objects writers/reader which was itself the fake console.
This is however pretty nasty. I would say that, if you truly want to launch things that look like separate consoles then you should actually do that and launch a new process for each one with a glue back end to manage them (somewhat similar to the concept of Chrome's back end processes per tab).
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?
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.
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.
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.
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
}