Why Would C# Processstartinforedirectstandardoutput Cause Xcopy Process to Fail

Why would C# ProcessStartInfoRedirectStandardOutput cause xcopy process to fail

There is an obscure post on the MSDN forums that seems to indicate that there may be a glitch with XCOPY itself -- if you redirect XCOPY's STDOUT, you must also redirect STDIN.

(note: I'm marking this a community wiki, so somebody who knows ruby could write some example code to redirecting STDIN for system())

XCopy does not work with UseShellExecute = false

I've tested your exact code, and appear to be able to receive data just fine. However, since the read occurs asynchronously, it is possible for WaitForExit(...) to return before you have read all of the data. It appears that the end of the data is signalled by the Data property of the DataReceivedEventArgs passed to the OutputDataReceived event handler being null.

It is also worth noting that if xcopy requests input from the user (e.g. in the case of a file with the same name existing in the destination) it appears that no data is returned. You may want to check for this in your batch file, or also handle data from the Standard Error stream.

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

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.

Start Process from Service hung UseShellExecute false

@Gusman: Add you comment as answer, you brought me to the correct answer. Then I can accept your comment as answer.

To the down-voter: Explanation why would be appreciated.

To all: I added some code to start the new process as a thread. In this case it make sense to start it in another thread to grab `StandardError messages but do not block the main process (which is a service in my case that starts many sub processes).

      // start as new thread to prevent blocking
var ths = new ThreadStart(() =>
{
mProcess.Start();
Pid = mProcess.Id;

// write pid file
File.WriteAllText(RubyDir + @"\tmp\pids\" + Port + @".pid", Pid.ToString());

using (var reader = mProcess.StandardError)
{
var errorMsg = reader.ReadToEnd();
if (errorMsg.Length > 0) _logger.ToLog("", Company, errorMsg, "SOLR.log", "service");
}
});
var th = new Thread(ths);
th.Start();

Cannot get Process to Execute before input stream is closed

Sorry took a little longer than I expected. This is a python oddity (i.e. you don't see this behavior in cmd). You need to add the '-i' switch to python when you start it. Here is a full working example.

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace stackoverflow1 {
class Program {

static void Main(string[] args) {
var exe = "python";
var arguments = "-i";

Process p = new Process();
p.StartInfo = new ProcessStartInfo() {
FileName = exe,
Arguments = arguments,
UseShellExecute = false,
RedirectStandardInput = true,
RedirectStandardOutput = true,
RedirectStandardError = true,
StandardOutputEncoding = Encoding.UTF8,
StandardErrorEncoding = Encoding.UTF8,
CreateNoWindow = false,
};

p.OutputDataReceived += new DataReceivedEventHandler(
delegate (object sendingProcess, DataReceivedEventArgs outLine) {
Console.WriteLine("{0}: {1}", exe, outLine.Data);
});

p.ErrorDataReceived += new DataReceivedEventHandler(
delegate (object sendingProcess, DataReceivedEventArgs errLine) {
Console.WriteLine("Error: " + errLine.Data);
});

p.Start();
p.BeginOutputReadLine();
p.BeginErrorReadLine();

StreamWriter sw = p.StandardInput;
sw.AutoFlush = true; //does nothing

if (exe == "cmd") {
sw.WriteLine("echo hello");
sw.WriteLine("echo 2+2");
sw.WriteLine("echo Goodbye");
}
else { // assume python
sw.WriteLine("print('Hello')");
sw.WriteLine("2+2");
sw.WriteLine("print('Printing from python')");
sw.WriteLine("print('Goodbye')");
}
sw.Flush();

System.Threading.Thread.Sleep(200);
Console.WriteLine("Closing");
sw.Close();

Console.ReadKey();
}
}
}

Problem if I run a process for second time, increase in memory usage c#

After so long and puling my hair of I decided to try something else to resolve the problem.
I created a new application with only this method with a button click to test if it would hang on the second attempt to compile the script. My surprise was that the problem was gone.

I decide then to try to reproduce my error by adding a few more actions from the original application. As soon I added the output.Clear(); it started to hang, problem found

I also tried to do output.Text = ""; and it will still started to hang.



Related Topics



Leave a reply



Submit