StandardOutput.ReadToEnd() hangs in one machine but never in another - c#

Below codes have been always working in one environment.
Now we switched to a new environment (new VM), this codes do not work any more, it just hangs there until I manually close the pop-up window from cmd.exe. Obviously, there is some dead lock. But why it only happens in the new environment?? Even now it still works in the old environment.
public static void Main()
{
Process p = new Process()
{
StartInfo = new ProcessStartInfo()
{
FileName = "c:\\windows\\System32\\cmd.exe",
Arguments = "/C START \"exeName\" /D %SystemDrive%\\somefolder start.bat",
UseShellExecute = false,
RedirectStandardOutput = true,
RedirectStandardError = true,
WorkingDirectory = "c:\\windows\\System32",
CreateNoWindow = true
}
};
p.Start();
string cv_error = null;
Thread et = new Thread(() => { cv_error = p.StandardError.ReadToEnd(); });
et.Start();
string cv_out = null;
Thread ot = new Thread(() => { cv_out = p.StandardOutput.ReadToEnd(); });
ot.Start();
p.WaitForExit();
Console.WriteLine("process finish " + p.HasExited); // This line prints "process finish true" successfully
ot.Join(); // Stuck here until I manually close the popup window. But it works in another machine with this popup window stay open
et.Join();
Console.WriteLine("success" + p.ExitCode);
Console.ReadLine();
}
The start.bat looks like
#echo off
Echo "something"
mklink /D Logs "D:/logs"
Echo "Starting"
cd %~dp0\someFolder
.\ExeToInstallTools.exe arg1 // it will popup a console window showing the progress and logs
IF ERRORLEVEL 1 goto error_handler
Exit /B 0
:error_handler
Echo "Failed"
Exit /B 1
UPDATE:
I have try to use some stackTrace tool to find the difference: when my app (process=4736) start the cmd process, cmd.exe /C turns into cmd.exe /K, it does not happen in the old machine.
StackTraceToolView

Related

C# Process is not stopping

I am using the below code C# Process instance to do a CSV import for PostgreSQL.
Process process = new Process()
{
StartInfo = new ProcessStartInfo
{
FileName = #"cmd.exe",
Arguments = $"/c cat \"{filePath}\" | psql -h 127.0.0.1 -U {user} -d {dbname} -w -c \"copy data_temp from stdin csv header\" ",
RedirectStandardOutput = true,
UseShellExecute = false,
CreateNoWindow = true,
}
};
process.Start();
string result = process.StandardOutput.ReadToEnd();
process.WaitForExit();
process.Dispose();
It works but I look in task manager and after a while there is lot of PostgreSQL processes running and eventually the database gets locked.
Am I not closing the process down properly? How can I ensure it doesn't stay open?
Not to sure if this could help or not but here are two examples I have of killing processes via msiexec and Exe.
Uninstalling Msiexec.exe files…
Process x = new Process();
x.StartInfo.FileName = "msiexec.exe";
x.StartInfo.Arguments = "/qb /x {81681F4C-83F1-4F22-9AEB-C7DA7C372EA2}";[quiet uninstall]
x.Start();
x.WaitForExit();
and
Uninstalling exe (file path method, not msiexec)
Process a = new Process();
a.StartInfo.FileName = JPRO_8_5_0; //defined in a string before hand.
a.StartInfo.Arguments = "/uninstall /quiet";
a.Start();
a.WaitForExit();
You can try making the filename a string that is defined before instead of having it as #"cmd.exe", that might help!

Run "sw-precache" command from c#

I want to generate "service-worker.js" using sw-precache
from command line (cmd.exe) I run this command and output is :
Total precache size is about 145 kB for 35 resources.
service-worker.js has been generated with the service worker contents.
When I run this command from C# output is empty, here is my code:
Process proc = new Process
{
StartInfo = new ProcessStartInfo
{
FileName = #"cmd.exe",
Arguments = #"/c sw-precache",
UseShellExecute = false,
RedirectStandardOutput = true,
RedirectStandardError = true,
CreateNoWindow = true,
WorkingDirectory = Path.GetFullPath(myDir)
}
};
proc.Start();
proc.WaitForExit();
string output = proc.StandardOutput.ReadToEnd();
If I run command like "dir" in Arguments = #"/c dir", output contains message from dir command,
what I do wrong?
Edit:
In Console Application, output is returned normally, but not in Web Application
WaitForExit first then read the output. It stays after the process has exited.

Kill Process in ffmpeg in c#

I'm using Process class to execute commands in ffmpeg like this:
string command = "/C ffmpeg -re -i test.mp4 -f mpegts udp://127.0.0.1:" + port.Text;
process.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
process.StartInfo.Arguments = command;
process.Start();
this code streams video to network, but I want to stop streaming when I click on button
I used process.kill() but the process still streaming even if I closed application
How can I stop process in background or send ctrl+c to it ?
The leading "/C" indicates that you start it via cmd.exe?
In that case process corresponds to cmd which in turn starts ffmpeg. Thus killing cmd doesn't kill ffmpeg.
string command = "-re -i test.mp4 -f mpegts udp://127.0.0.1:" + port.Text;
process.StartInfo.FileName ="ffmpeg";
process.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
process.StartInfo.Arguments = command;
process.Start();
process.Kill(); should work then.
So I was going through the same trouble of starting and stopping ffmpeg process in my selenium Nunit test. After bit of struggle I was able to create a simple solution. Sending as "q" a input to the process window of ffmpeg gracefully stops the process and the video recording is not corrupt as well.
here is my c# code to start the ffmpeg and stop it after execution.
Create a bat file to start your ffmpeg (you will be calling this batfile from your c# code)
In you selenium test , create a recording class and 2 methods to start and stop the recording(in my case I was starting the bat file before all test as in calling the executeScreenRecordingBatFile method in onetimesetup attribute to start the recording and calling the StopScreenRecording method in onetimeteardown ) Sample code below.
using System.Diagnostics;
using System.IO;
namespace FunctionalTests
{
public class Recording
{
public static Process process;
public static void executeScreenRecordingBatFile()
{
try
{
process = new Process();
process.StartInfo.FileName = #"C:\Program Files (x86)\StartScreenRecording.bat";
process.StartInfo.CreateNoWindow = true;
process.StartInfo.RedirectStandardInput = true;// this required to send input to the current process window.
bool started = process.Start();
if (started==true)
{
Console.WriteLine("Bat file started");
}
}
catch (Exception ex)
{
Console.WriteLine(ex.StackTrace.ToString());
throw;
}
}
public static void StopScreenRecording()
{
StreamWriter myStreamWriter = process.StandardInput; // this required to send StandardInput stream, nothing fancy
myStreamWriter.WriteLine("q"); //this will send q as an input to the ffmpeg process window making it stop , please cross check in task manager once if the ffmpeg is still running or closed.
}
}
}
I created a method to kill ffmpeg process.
private void KillAllFFMPEG()
{
Process killFfmpeg = new Process();
ProcessStartInfo taskkillStartInfo = new ProcessStartInfo
{
FileName = "taskkill",
Arguments = "/F /IM ffmpeg.exe",
UseShellExecute = false,
CreateNoWindow = true
};
killFfmpeg.StartInfo = taskkillStartInfo;
killFfmpeg.Start();
}
Just call it wherever you want.
UPDATE 1
In order to kill just one instance of the FFMPEG process, we need to get it's PID first. When you define your ffmpeg process for streaming, define it in the global scope and use following command to get the PID after it is initialized.
int myProcessId = FfmpegProcess.Id;
Then call the following
private void KillFFMPEGByPID(int PID)
{
Process killFfmpeg = new Process();
ProcessStartInfo taskkillStartInfo = new ProcessStartInfo
{
FileName = "taskkill",
Arguments = "/PID " + Convert.ToString(PID) + " /T",
UseShellExecute = false,
CreateNoWindow = true
};
killFfmpeg.StartInfo = taskkillStartInfo;
killFfmpeg.Start();
}
This will kill only the process with the given PID. /T flag at the end of the argument determines that whole process tree will be killed.
Cheers

How to let the command window open while executing command prompt scripts from C#?

I am facing a strange issue. I have an application in which a method executes some of command prompt commands but they are not executing in an appropriate way. The code snippet looks like
private void encryptAndWrite(String FileName)
{
string strEntry = FileName.Replace("\\web.config", ""); // Let the user assign to this string, for example like "C:\Users\cnandy\Desktop\Test\Websites\AccountDeduplicationWeb"
Process p = new Process()
{
StartInfo = new ProcessStartInfo("cmd.exe")
{
RedirectStandardInput = true,
RedirectStandardOutput = true,
UseShellExecute = false,
CreateNoWindow = true
}
};
p.Start();
p.StandardInput.WriteLine(#"cd C:\Windows\Microsoft.NET\Framework64\v4.0.30319");
p.StandardInput.WriteLine("aspnet_regiis.exe -pc \"CustomKeys12\" -exp");
p.StandardInput.WriteLine("aspnet_regiis.exe -pa \"CustomKeys12\" \"NT AUTHORITY\\NETWORK SERVICE\"");
p.StandardInput.WriteLine("aspnet_regiis -pef \"connectionStrings\" {0} -prov \"CustomEncryptProvider\"",strEntry);
p.StandardInput.WriteLine("aspnet_regiis -px \"CustomKeys12\" {0} -pri",KeyFileName);
p.StandardInput.WriteLine("exit");
Thread.Sleep(7000);
updateTextBox.ReadOnly = true;
updateTextBox.Text = String.Empty;
updateMessageLabel.Text = String.Empty;
showConfig(FileName);
}
Essentially the last command should overwrite a file which is supplied by
KeyFileName
each time the command executes successfully. But it is not.
If I hard code it like
p.StandardInput.WriteLine("aspnet_regiis -px \"CustomKeys12\" \"C:\\Users\\Chiranjib\\Desktop\\XMLKey\\CustomEncryptKey.xml\" -pri");
it executes successfully.
So is there a way where I can let the command window open so that I can see where the commands are going wrong ? I though tried CreateNoWindow = false
but it does not show the command by command execution.
Thanks in advance.

How do I use ProcessStartInfo to run a batch file?

But it doesn't work -meaning the java code is not executed.
Although the batch file runs fine when clicked in Windows explorer or when run in command line ..
Since this works fine when the batch file is a single DOS command, I think this is somehow related to the fact that the Java code needs ~20 minutes to run.
I'm using the following code
var si = new ProcessStartInfo();
si.CreateNoWindow = true;
si.FileName = batchFileName;
si.UseShellExecute = false;
Process.Start(si);
What am I doing wrong?
Set UseShellExecute to true, so it loads cmd.exe to run the batch file.
Check this - a batch file wrapper of ProcessStartInfo:
C:\>ProcessStartJS.bat "cmd.exe" -arguments "/c pause" -style Minimized -priority High -newWindow yes -useshellexecute yes
Started: cmd.exe /c pause
PID:6540
As Lucas Jones mentioned in the comments, if you don't want to use ShellExecute, do it like this:
string fullBatPath = #"C:\path with space\file.bat";
var process = new Process()
{
StartInfo = new ProcessStartInfo
{
FileName = "cmd.exe",
Arguments = $"cmd /C \"{fullBatPath}\"",
UseShellExecute = false,
CreateNoWindow = true,
}
};
process.Start();

Categories

Resources