When run a program in C#, all the messages go to the standard output, but the standard error contains nothing

c# output error message
standard error has not been redirected c#
c# process standarderror
c# redirect standard output of running process
cannot mix synchronous and asynchronous operation on process stream.
c# process exit code
standardout has not been redirected or the process hasn't started yet.
useshellexecute

My question is different with the one identified. Obviously I have called "BeginErrorReadLine" method (I mark it in the code below).

I want to parse the result produced by Handle


Command line

When run in a command line environment, it will output something like:

> handle64 -p [PID]

 

Nthandle v4.11 - Handle viewer

Copyright (C) 1997-2017 Mark Russinovich

Sysinternals - www.sysinternals.com

 

  10: File     C:\Windows

  1C: File     C:\Windows\SysWOW64

[PID] is any running process ID

The output is seperated.

First 5 lines (include empty lines) go to the standard error, last 2 lines go to the standard output.

So I can strip the header by redirecting:

> handle64 -p [PID] 2>nul

  10: File     C:\Windows

  1C: File     C:\Windows\SysWOW64


Winform application

Then I try to implement this command in a C# winform application:

Stream streamOut, streamErr;

var p = Process.Start(new ProcessStartInfo
{
    FileName = "handle64.exe",
    Arguments = "-p [PID]",
    CreateNoWindow = true,
    UseShellExecute = false,
    RedirectStandardOutput = true,
    RedirectStandardError = true,
});

p.OutputDataReceived += (sender, e) =>
{
    streamOut.Write("Output => " + e.Data);
};

p.ErrorDataReceived += (sender, e) =>
{
    streamErr.Write("Error => " + e.Data);
};

p.BeginOutputReadLine();
p.BeginErrorReadLine(); // !!!
p.WaitForExit();

Then I find everything go to the standard output.


Question

Ok, I can seperate the header and the body by code.

The question is why the program's output behaves different between the 2 environments?

Can I make the result in the winform application behaves like it in the command line?


Update

For Damien's comment, I try to run the program via 'cmd', unfortunately I get the same result:

var p = Process.Start(new ProcessStartInfo
{
    FileName = "cmd",
    Arguments = "/C handle64.exe -p [PID]",
    CreateNoWindow = true,
    UseShellExecute = false,
    RedirectStandardOutput = true,
    RedirectStandardError = true,
});

...

In output window:

Output =>

Output => Nthandle v4.11 - Handle viewer

Output => Copyright (C) 1997-2017 Mark Russinovich

Output => Sysinternals - www.sysinternals.com

Output =>

Output =>   10: File     C:\Windows

Output =>   1C: File     C:\Windows\SysWOW64

Error =>

This is just a sample to illustrate the problem I alluded to in my comments. It's not a fix since I don't believe there is a trivial way to fix this. I've created Main in my scratch program (called PlayAreaCSCon). If it's called with no parameters, it's acting a way similar to what I suspect Handle64.exe is doing. When called with a parameter, it contains code similar to your own, but it then launches a copy of itself with no parameters:

using System;
using System.Diagnostics;
using System.IO;
using System.Runtime.InteropServices;

namespace PlayAreaCSCon
{
    class Program
    {
        [DllImport("kernel32.dll")]
        static extern IntPtr GetConsoleWindow();
        static void Main(string[] args)
        {
            if (args.Length == 0)
            {
                Console.Out.WriteLine("Hello");
                if (GetConsoleWindow() == IntPtr.Zero)
                {
                    Console.Out.WriteLine("No Console window");
                }
                else
                {
                    Console.Error.WriteLine("We have a console window");
                }
            }
            else
            {
                Process p = Process.Start(new ProcessStartInfo
                {
                    FileName = "PlayAreaCSCon.exe",
                    Arguments = "",
                    CreateNoWindow = true,
                    UseShellExecute = false,
                    RedirectStandardOutput = true,
                    RedirectStandardError = true,
                });

                TextWriter streamOut = Console.Out;
                TextWriter streamErr = Console.Error;
                p.OutputDataReceived += (sender, e) =>
                {
                    streamOut.WriteLine("Output => " + e.Data);
                };

                p.ErrorDataReceived += (sender, e) =>
                {
                    streamErr.WriteLine("Error => " + e.Data);
                };

                p.BeginOutputReadLine();
                p.BeginErrorReadLine(); // !!!
                p.WaitForExit();
            }
        }
    }
}

In a command prompt, I have the following session:

C:\Dev\PlayAreaCSCon\PlayAreaCSCon\bin\Debug>PlayAreaCSCon.exe
Hello
We have a console window

C:\Dev\PlayAreaCSCon\PlayAreaCSCon\bin\Debug>PlayAreaCSCon.exe a
Error =>
Output => Hello
Output => No Console window
Output =>

So even here, if Handle64.exe is calling GetConsoleWindow or any morally equivalent function, it can detect that it's not connected to a console and exhibit different behaviour. The only way you might let it get a console window would be to set CreateNoWindow to false, which I gather you probably wouldn't want to do.

Since Handle64 is closed source it's difficult to confirm that this is the specific check it's performing either. There's no non-trivial fix to this from the calling side.

Process.StandardError Property (System.Diagnostics), Gets a stream used to read the error output of the application. The StandardError stream has not been defined for redirection; ensure RedirectStandardError StandardError; // Read the standard error of net.exe and write it on to console. The last two examples in this section use the Start method to launch an executable  Imports System.IO Public Class ExpandTabs Private Const tabSize As Integer = 4 Private Const usageText As String = "Usage: EXPANDTABSEX inputfile.txt outputfile.txt" Public Shared Sub Main(args() As String) Dim writer As StreamWriter = Nothing If args.Length < 2 Then Console.WriteLine(usageText) Exit Sub End If Try writer = New StreamWriter

Not the answer of your question, but just a suggestion to achieve what you are trying do (i.e only get handle information in Winform application):

handle tool has -nobanner switch, you can use that to skip copyright message information.

handle64.exe -pid 11624 -nobanner

Console.Error Property (System), It redirects the standard input and output streams to files, but uses the Error property to write the standard error stream to the console. It can be launched from the  When run a program in C#, all the messages go to the standard output, but the standard error contains nothing (3) As stated by Damien: CreateNoWindow = false, Let it create the window the immediately hide it. We could create it offscreen, but it would still show on the taskbar.

As stated by Damien: CreateNoWindow = false,

Let it create the window the immediately hide it. We could create it offscreen, but it would still show on the taskbar.

Note: this code may be no better than letting the Window appear and disappear naturally.

At the top of the class add:

[DllImport("user32.dll")]
static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);

Then your code becomes:

var p = Process.Start(new ProcessStartInfo
{
    FileName = "cmd",
    Arguments = "/C handle64.exe -p [PID]",
    CreateNoWindow = false,
    UseShellExecute = false,
    RedirectStandardOutput = true,
    RedirectStandardError = true,
});
p.WaitForInputIdle();
IntPtr windowHandle = p.MainWindowHandle;
if(windowHandle == 0) throw new Exception("This did not work");
// use win32 API's to hide window (May still flicker)
ShowWindow(windowHandle,0);
// ...

I am unable to test this, since I am only running Linux at the moment. If the exception doesn't fire, you may see a flicker of a window, but you should have the proper output.

The other way I know of doing this involves inserting handlers into the Win32 message pump and respond to the specific process telling it what it needs to know to think it has a proper window when it does not. I will not publicly post any code related to this technique. Any errors would cause Windows to become unstable.

ProcessStartInfo.RedirectStandardOutput Property (System , Gets or sets a value that indicates whether the textual output of an application is Run "csc.exe /r:System.dll /out:sample.exe stdstr.cs". call the WaitForExit method to ensure that the output buffer has been flushed. There is a similar issue when you read all text from both the standard output and standard error streams. Generally, when a command starts, three files are already open: stdin (standard input), stdout (standard output), and stderr (standard error). If you want to redirect standard input or standard output, you can use the <, >, or > > symbols.

I made some changes to your code:

Stream streamOut, streamErr;

var p = Process.Start(new ProcessStartInfo
{
    FileName = "handle64.exe",
    Arguments = "-p [PID]",
    CreateNoWindow = true,
    UseShellExecute = false,
    RedirectStandardOutput = true,
    RedirectStandardInput = true, // even if no writing to std::in, still need this
    RedirectStandardError = true,
});

p.OutputDataReceived += (sender, e) =>
{
    streamOut.Write("Output => " + e.Data);
};
p.BeginOutputReadLine();

p.ErrorDataReceived += (sender, e) =>
{
    streamErr.Write("Error => " + e.Data);
};

p.BeginErrorReadLine(); 

p.WaitForExit();
p.StandardInput.Close(); // call this before WaitForExit
p.WaitForExit();

Writing Error Messages to Standard Error Instead of Standard Output , At the moment, we're writing all of our output to the terminal using the println! macro. the successful output of a program to a file but still print error messages to the The way to demonstrate this behavior is by running the program with > and contains nothing, which is the behavior we expect of command line programs. (Please note, there is no comma , after the words STDOUT and STDERR in this expression!). If you run this script (perl program.pl) you will see this on the screen: Welcome to our little program Could not open file

Standard streams, For example, output of a program in a pipeline is redirected to input of the next program, but errors from each program still go directly to the text terminal. It is  If there is standard output, you might suspect that there is standard input as well. That’s correct. The easiest way to read it is to use System.Console class again.

Batch files, Standard Error is the stream where many (but not all) commands send their error all Standard Output to the NUL device, which does nothing but discard it. versions, but in Windows XP I get the following error message: To get rid of screen output sent directly to the Console, either run the program in a  You can print the errors and standard output to a single file by using the "&1" command to redirect the output for STDERR to STDOUT and then sending the output from STDOUT to a file: dir file.xxx 1> output.msg 2>&1

The 10 Most Common Mistakes in C# Programming, Don't fall into one of these C# programming mistakes that even savvy and run times, results in the majority of typical C# programming errors being Many (but not all) value types have an IsEmpty property which you can check Common C# Programming Mistake #6: Getting confused or faked out by extension methods. When a Process writes text to its standard stream, that text is normally displayed on the console. By redirecting the StandardOutput stream, you can manipulate or suppress the output of a process. For example, you can filter the text, format it differently, or write the output to both the console and a designated log file.

Comments
  • Why do you think the output should be separated in your program if you finally write everything into the same stream ?
  • @Dmytro Not my program, but theirs, called "Handle". you can download it via the link. I just run it in my program. so the stream is written by that one. I think the same program usually writes message to the same stream.
  • I'm asking actually about your program which does Trace.Writeline for both error and output messages.
  • I'm almost certain that if your description is accurate, then it's a decision being made by the target application. It's possible to determine if you're actually attached to an interactive console (though not terribly easy in .NET) and to use that to suddenly decide "hey, I'm going to just send everything to standard output" if you're not.
  • What happens if you replace handle64 program with another program with known result? For, example, C++ cout << "StandardOutput" << endl; cerr << "StandardError" << endl; Maybe handle64 program contains some tricks as mentioned by @Damien_The_Unbeliever.