I am running an exe program within my C# console program, which if I were running it via the CMD, it would write to its own log, plus a few messages to the CMD window. When I read the standardOutput within my program, I am able to see the CMD messages, but the log to which the process should be writing to is not being created. In other words, my external process writes to its own log, which is built into this black box utility, so now that I want to run it from my console program, the log is not being created. Has anyone encountered this issue and have some suggestion as to how it can be resolved? I cannot loose this log as it is the utility's log; separate from my program. Here is a snipped of my code:
ProcessStartInfo startInfo = new ProcessStartInfo();
startInfo.CreateNoWindow = false;
startInfo.UseShellExecute = false;
startInfo.FileName = processName;
startInfo.RedirectStandardOutput = true;
startInfo.Arguments = " " + dbName + " " + pw + " " + clientFile;
try
{
using (Process exeProcess = Process.Start(startInfo))
{
using (StreamReader reader = exeProcess.StandardOutput)
{
exeProcess.Start();
exeProcess.WaitForExit();
string result = reader.ReadToEnd();
Console.WriteLine(result);
}
}
}
catch (Exception e)
{
Console.WriteLine("Error: " + e);
}
You have to read the result after the process has finished:
exeProcess.Start();
exeProcess.WaitForExit();
string result = reader.ReadToEnd();
Console.WriteLine(result);
Related
I've a free trial launcher for the Final Fantasy XIV game. Now I want to launch it through process.start in a windows service in C#. the process starts successfully, as I can see it in the windows task manager, but it does not launch the setup file. Here is the code I've tried.
try {
var process = new Process();
var startInfo = new ProcessStartInfo
{
WindowStyle = ProcessWindowStyle.Normal,
FileName = "cmd.exe",
Arguments = "/C " + setupFile + " /DIR=" + installLocation,
};
process.StartInfo = startInfo;
process.Start();
process.WaitForExit();
}
catch (Exception ex)
{
Logger.Log.Error("Error Installing game.", ex);
}
Where setupfile is the complete path for ffxivsetup_ft.exe.
Try this code :
ProcessStartInfo startInfo = new ProcessStartInfo(path);
Process.Start(startInfo);
I am trying to execute a command through c# code on cmd window other than the console window(opens on Ctrl+F5). On executing command it asks for username and password. Now, How should i pass username and password one by one.
And on completion of process it generates 2 lines of output which is to be read inside c# code to be used later on. Updated Code written so far given as:
using System;
using System.IO;
using System.Diagnostics;
namespace ios
{
class Program
{
static void Main(string[] args)
{
ProcessStartInfo procStartInfo = new ProcessStartInfo();
procStartInfo.FileName = "cmd.exe";
procStartInfo.Arguments = "/C java -jar Reporter.jar p=Reporter.properties m=Normal Sales.viewToken";
procStartInfo.UseShellExecute = false;
procStartInfo.RedirectStandardOutput = true;
procStartInfo.RedirectStandardError = true;
procStartInfo.RedirectStandardInput = true;
using (Process process = new Process())
{
process.StartInfo = procStartInfo;
process.ErrorDataReceived += new DataReceivedEventHandler(OutputHandler);
process.Start();
StreamWriter streamWriter = process.StandardInput;
streamWriter.WriteLine("myusername");
streamWriter.WriteLine("password");
streamWriter.Close();
process.BeginErrorReadLine();
process.WaitForExit();
}
}
static void OutputHandler(object sendingProcess, DataReceivedEventArgs outLine)
{
Console.WriteLine("Output shown : " + outLine.Data);
if (outLine.Data != null && outLine.Data.Contains("AccessToken"))
{
Console.WriteLine("Line Echoed : " + outLine.Data);
}
if (outLine.Data != null && outLine.Data.Contains("Expiration Date"))
{
Console.WriteLine("Line Echoed : " + outLine.Data);
}
}
}
}
Now, It is working perfectly with other commands. But the command that i have shown(java -jar Reporter.jar p=Reporter.properties m=Normal Sales.viewToken) is not taking input as expected. It does not show any output on executing this program. How would i be able to pass inputs and store the output ?
Output strings to your command:
cmd.StandartInput.WriteLine("Please Input UserName:");
Get strings that users input in Command:
string s_UserName = cmd.StandardOutput.ReadToEnd();
And the same for password.
Get your processus base streams :
StreamWriter sw = cmd.StandardInput
StreamReader sr = sr.StandardOutput
Sending/reading is as easy as sr.ReadLine, sw.Writeline !
Use input/output rederiction
cmd.StartInfo.RedirectStandardInput = true;
cmd.StartInfo.RedirectStandardOutput = true;
And the use the cmd.StandardInput and cmd.StandardOutput to read/write to the process.
I'm trying to launch an application from another using System.Diagnostic.Process that way :
if (this.isRequiredFieldFilled())
{
ProcessStartInfo start = new ProcessStartInfo();
MessageBox.Show("PIC" + up.pathPIC);
start.FileName = up.pathPIC;
//start.WindowStyle = ProcessWindowStyle.Normal;
//start.CreateNoWindow = true;
int exitCode;
try
{
using (Process proc = Process.Start(start))
{
proc.WaitForExit();
exitCode = proc.ExitCode;
MessageBox.Show(exitCode.ToString());
}
}
catch (Exception ex)
{
MessageBox.Show("Exception -> " + ex.Message);
}
}
else
{
//TODO Handle input
}
I can see the spinner but nothing apear and i receive the return code -> -532462766
I don't really understand because, when I double click on this application there is no problem, and if I launch another app from my process it work well too.
Did I miss something ?
I'm executing a batch file with the following code:
using (var process = new Process())
{
process.StartInfo.CreateNoWindow = true;
process.StartInfo.FileName = "cmd.exe";
process.StartInfo.Arguments = "/c \"\"" + batchFile + "\"\"";
process.StartInfo.WorkingDirectory = AppDomain.CurrentDomain.BaseDirectory;
process.StartInfo.UseShellExecute = false;
process.StartInfo.RedirectStandardOutput = true;
process.StartInfo.RedirectStandardError = true;
var output = new StringBuilder();
var error = new StringBuilder();
using (var outputWaitHandle = new AutoResetEvent(false))
using (var errorWaitHandle = new AutoResetEvent(false))
{
process.OutputDataReceived += (sender, e) =>
{
if (e.Data == null)
{
outputWaitHandle.Set();
}
else
{
output.AppendLine(e.Data);
}
};
process.ErrorDataReceived += (sender, e) =>
{
if (e.Data == null)
{
errorWaitHandle.Set();
}
else
{
error.AppendLine(e.Data);
}
};
process.Start();
process.BeginOutputReadLine();
process.BeginErrorReadLine();
if (process.WaitForExit(30000) &&
outputWaitHandle.WaitOne(30000) &&
errorWaitHandle.WaitOne(30000))
{
Log("Batch file exit code: " + process.ExitCode + ".\nOutput: " + output + ".\nError ouput: " + error);
}
else
{
Log("The batch file timed out.");
}
}
}
This code executes a batch file, and waits for it to complete. And it works fine when my batch file only outputs to a text file. But if my batch file contains the line start "C:\Windows\System32" notepad.exe, it times out. Why?
EDIT
I just realized that it hangs even if all I have in my batch file is notepad.exe, but it works fine if I'm writing to a text file. The exit code is InvalidOperation
EDIT
Even with this simple code, it won't open notepad. It doesn't throw any exception or anything either...
string notepadPath = Path.Combine(Environment.SystemDirectory, "notepad.exe");
if (System.IO.File.Exists(notepadPath))
Process.Start(notepadPath);
Check the Task Manager stats tab - I'm sure there are a lot of notepads there.
You are creating the Process with StartInfo.CreateNoWindow = true;. This prevents the notepad window to open, as no window - no notepad. Also the same behaviour is for UseShellExecute = false;.
Remove these lines and try out another time (and make sure if there is a notepadPath file exists, and the batch, if you run it manually, opens the notepad).
According the MSDN:
// This code assumes the process you are starting will terminate itself.
// Given that is is started without a window so you cannot terminate it
// on the desktop, it must terminate itself or you can do it programmatically
// from this application using the Kill method.
So you simply creating your process and batch is waiting for it to close, which won't never happen.
I am using following code to write the PATH, EXECUTABLE NAME and ARGUMENTS to a batch file and execute it through CMD using c#. The problem is sometimes the application dosent starts up after executing the batch file. And the c# code dosent give me exception or any notification.
For which i want to get the Exitcode from CMD to determine if the commands executed properly.
How can i determine Exit code ?
public void Execute()
{
try
{
string LatestFileName = GetLastWrittenBatchFile();
if (System.IO.File.Exists(BatchPath + LatestFileName))
{
System.Diagnostics.ProcessStartInfo procinfo = new System.Diagnostics.ProcessStartInfo("cmd.exe");
procinfo.UseShellExecute = false;
procinfo.RedirectStandardError = true;
procinfo.RedirectStandardInput = true;
procinfo.RedirectStandardOutput = true;
System.Diagnostics.Process process = System.Diagnostics.Process.Start(procinfo);
System.IO.StreamReader stream = System.IO.File.OpenText(BatchPath + LatestFileName);
System.IO.StreamReader sroutput = process.StandardOutput;
System.IO.StreamWriter srinput = process.StandardInput;
while (stream.Peek() != -1)
{
srinput.WriteLine(stream.ReadLine());
}
Log.Flow_writeToLogFile("Executed .Bat file : " + LatestFileName);
process.WaitForExit(1000);
if (process.ExitCode != 0)
{
int iExitCode = process.ExitCode;
}
stream.Close();
process.Close();
srinput.Close();
sroutput.Close();
}
else
{
ExceptionHandler.writeToLogFile("File not found");
}
}
catch (Exception ex)
{
ExceptionHandler.writeToLogFile(System.Environment.NewLine + "Target : " + ex.TargetSite.ToString() + System.Environment.NewLine + "Message : " + ex.Message.ToString() + System.Environment.NewLine + "Stack : " + ex.StackTrace.ToString());
}
}
_________________Update___________________
script inside Batchfile : [Note that Notepads.exe is wrong to get the error ]
START
Notepads.EXE
"if "%ERRORLEVEL%" == "1" exit /B 1"
It is much easier to run the process directly instead of using creating a batch file that you later execute since you lose some control since you are using a batch script layer.
Use this code instead:
/// <summary>
/// Execute external process.
/// Block until process has terminated.
/// Capture output.
/// </summary>
/// <param name="binaryFilename"></param>
/// <param name="arguments"></param>
/// <param name="currentDirectory"></param>
/// <param name="priorityClass">Priority of started process.</param>
/// <returns>stdout output.</returns>
public static string ExecuteProcess(string binaryFilename, string arguments, string currentDirectory, ProcessPriorityClass priorityClass)
{
if (String.IsNullOrEmpty(binaryFilename))
{
return "no command given.";
}
Process p = new Process();
p.StartInfo.FileName = binaryFilename;
p.StartInfo.Arguments = arguments;
p.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
p.StartInfo.RedirectStandardOutput = true;
p.StartInfo.RedirectStandardError = true;
p.StartInfo.UseShellExecute = false;
if (!String.IsNullOrEmpty(currentDirectory))
p.StartInfo.WorkingDirectory = currentDirectory;
p.StartInfo.CreateNoWindow = false;
p.Start();
// Cannot set priority process is started.
p.PriorityClass = priorityClass;
// Must have the readToEnd BEFORE the WaitForExit(), to avoid a deadlock condition
string output = p.StandardOutput.ReadToEnd();
p.WaitForExit();
if (p.ExitCode != 0)
{
throw new Exception(String.Format("Process '{0} {1}' ExitCode was {2}",
binaryFilename,
arguments,
p.ExitCode));
}
//string standardError = p.StandardError.ReadToEnd();
//if (!String.IsNullOrEmpty(standardError))
//{
// throw new Exception(String.Format("Process '{0} {1}' StandardError was {2}",
// binaryFilename,
// arguments,
// standardError));
//}
return output;
}
I use it in a number of projects and it works like a charm.
If you HAVE to go the batch script route, make sure that the batch script set exitcode properly.
Does the Process.ExitCode property not give you what you want? Obviously you'd need to make sure that the batch file itself exits with the right exit code, mirroring the application it's running.
By the way, you should use using statements to make sure that all the relevant streams are closed in the face of exceptions - and I would suggest the asynchronous ways of reacting to data from the application, rather than synchronous IO. If you do stick to synchronous IO, you should have another thread reading from standard error - otherwise if the process writes a lot of data to standard error, it will block waiting for you to clear the buffer.
Use ExitCode like follows:
System.Diagnostics.Process proc = new System.Diagnostics.Process();
proc.StartInfo.FileName = #"usbformat.bat";
proc.StartInfo.UseShellExecute = false;
proc.StartInfo.CreateNoWindow = true; // change to false to show the cmd window
proc.Start();
proc.WaitForExit();
if (proc.ExitCode != 0)
{
return false;
}
else
{
return true;
}
System.Diagnostics.ProcessStartInfo psi = new System.Diagnostics.ProcessStartInfo(filename);
psi.RedirectStandardOutput = true;
psi.WindowStyle = System.Diagnostics.ProcessWindowStyle.Hidden;
psi.UseShellExecute = false;
System.Diagnostics.Process listFiles;
listFiles = System.Diagnostics.Process.Start(psi);
System.IO.StreamReader myOutput = listFiles.StandardOutput;
listFiles.WaitForExit(2000);
if (listFiles.HasExited)
{
string output = myOutput.ReadToEnd();
MessageBox.Show(output);
}
you can get it from procinfo.ExitCode