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 ?
Related
I am trying to implement piping behavior in C#.NET using Process and ProcessStartInfo classes. My intention is to feed the output of previous command to next command so that that command will process the input and return result. have a look into following code -
private static string Out(string cmd, string args, string inputFromPrevious)
{
string RetVal = string.Empty;
try
{
ProcessStartInfo psi = String.IsNullOrEmpty(args) ? new ProcessStartInfo(cmd) : new ProcessStartInfo(cmd, args);
psi.RedirectStandardOutput = true;
psi.RedirectStandardError = true;
psi.WindowStyle = ProcessWindowStyle.Hidden;
psi.UseShellExecute = false;
psi.RedirectStandardInput = string.IsNullOrEmpty(inputFromPrevious) ? false : true;
Process proc = new System.Diagnostics.Process();
proc.StartInfo = psi;
if (proc.Start())
{
if (!string.IsNullOrEmpty(inputFromPrevious))
{
proc.StandardInput.AutoFlush = true;
proc.StandardInput.WriteLine(inputFromPrevious); proc.StandardInput.WriteLine();
proc.StandardInput.Close();
}
using (var output = proc.StandardOutput)
{
Console.WriteLine("3. WAITING WAITING....."); < ---Code halts here.
RetVal = output.ReadToEnd();
}
}
proc.WaitForExit();
proc.Close();
}
catch (Exception Ex)
{
}
return RetVal; < ---This is "inputFromPrevious" to next call to same function
}
I am calling above code in loop for different commands and arguments. Is there any mistake in my code? I had looked similar as shown below but nothing worked for me as of now. Any help will be appreciated.
Piping in a file on the command-line using System.Diagnostics.Process
Why is Process.StandardInput.WriteLine not supplying input to my process?
Repeatably Feeding Input to a Process' Standard Input
I'm using a helper class for running external process:
class ExternalProcessRunner
{
static public string Run(string program, string parameters)
{
output = "";
error = "";
try
{
ProcessStartInfo startInfo = new ProcessStartInfo();
startInfo.CreateNoWindow = true;
startInfo.UseShellExecute = false;
startInfo.FileName = program;
startInfo.Arguments = parameters;
startInfo.WindowStyle = ProcessWindowStyle.Hidden;
startInfo.WindowStyle = ProcessWindowStyle.Minimized;
startInfo.RedirectStandardError = true;
startInfo.RedirectStandardOutput = true;
StringBuilder outputSB = new StringBuilder();
StringBuilder errorSB = new StringBuilder();
using (Process exeProcess = Process.Start(startInfo))
using (AutoResetEvent outputWaitHandle = new AutoResetEvent(false))
using (AutoResetEvent errorWaitHandle = new AutoResetEvent(false))
{
exeProcess.OutputDataReceived += (sender, e) =>
{
if (e.Data == null)
{
outputWaitHandle.Set();
}
else
{
outputSB.AppendLine(e.Data);
}
};
exeProcess.ErrorDataReceived += (sender, e) =>
{
if (e.Data == null)
{
errorWaitHandle.Set();
}
else
{
errorSB.AppendLine(e.Data);
}
};
exeProcess.Start();
exeProcess.BeginOutputReadLine();
exeProcess.BeginErrorReadLine();
exeProcess.WaitForExit();
outputWaitHandle.WaitOne();
errorWaitHandle.WaitOne();
output = outputSB.ToString();
error = errorSB.ToString();
}
}
catch (Exception e)
{
return e.Message;
}
return "";
}
static public string output;
static public string error;
}
It is used to run a perl script which accepts a filename, opens a file, writes some information and closes a file. Then C# code opens that file for reading. Sometimes I get an exception:
"The process cannot access the file 'tmp_file.txt' because it is being used by another process."
What can cause the problem? How to fix it? I think that I'm ensuring the ending of process which means freeing all handles.
Please check you have exited the process i.e. you released the file from the memory.
You can pass in a set number of seconds to wait for the process to exit. Then check if it has exited. If it hasn't, then try and kill the process.
In the example below, it waits for 1 minute for the process to exit. If it doesn't exit, then it sensd a command to close the main window and sleep for 2 seconds. If it still hasn't exited then it tries to kill the process.
At the stage the external process should be gone and the lock released on the file.
exeProcess.WaitForExit(1 * 60 * 1000);
if (!exeProcess.HasExited)
{
_log.Warn("External process has not completed after {0} minutes - trying to close main window", waitTimeMin);
exeProcess.CloseMainWindow();
System.Threading.Thread.Sleep(2000);
}
if (!exeProcess.HasExited)
{
_log.Warn("External process still has not completed - Killing process and waiting for it to exit...");
exeProcess.Kill();
exeProcess.WaitForExit();
}
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);
I would like to start a process and read the standard output but also have this read output show up in the console window of the spawned process. Currently using process.StartInfo.RedirectStandardOutput = true; combined with BeginOutputReadLine() causes the output not to show up in the console window. Which is undesirable. Does anyone know how to do this or if it's even possible?
To clarify for the comments.
I have a function that responds to the output from the process, that I set with:
ProcessHandle.OutputDataReceived += new DataReceivedEventHandler(ProcessHandle_OutputDataReceived);
void ProcessHandle_OutputDataReceived(object sender, DataReceivedEventArgs e)
{
... //React to output here.
}
But in doing so the output doesn't make it to the console window of the spawned process, is there any way to manually feed it back to that console so it shows up as if my application had not intercepted it?
var pi = new ProcessStartInfo
{
FileName = prog,
Arguments = args,
UseShellExecute = false,
CreateNoWindow = true,
RedirectStandardOutput = true,
RedirectStandardError = false
};
var proc = new Process { StartInfo = pi };
try
{
if (!proc.Start())
{
throw new ApplicationException("Starting proc failed!");
}
Console.WriteLine(proc.StandardOutput.ReadToEnd());
proc.WaitForExit();
if (proc.ExitCode != 0)
{
//throw new ApplicationException(String.Format("proc returned exit code {0}", proc.ExitCode));
}
}
catch (Exception ex)
{
throw new ApplicationException("Unknown problem in proc", ex);
}
finally
{
if (!proc.HasExited)
proc.Kill();
}
I am writing a InstallerClass using C# as a custom action for my installer, and I can successfully run an external exe (installation) using the InstallerClass, but when I try to use /quiet in the InstallerClass, it does not install the exe. But I can successfully install this in silent mode using /quiet in the command prompt.
Is there any reason for this or otherwise how to install in silent mode using C#?
Following is the code I use within the Commit method (overriden):
Process p = new Process();
p.StartInfo.UseShellExecute = false;
p.StartInfo.FileName = pathExternalInstaller;
p.StartInfo.Arguments = "/quiet";
p.Start();
Here is what I use to do a quiet Install and Uninstall:
public static bool RunInstallMSI(string sMSIPath)
{
try
{
Console.WriteLine("Starting to install application");
Process process = new Process();
process.StartInfo.FileName = "msiexec.exe";
process.StartInfo.Arguments = string.Format(" /qb /i \"{0}\" ALLUSERS=1", sMSIPath);
process.Start();
process.WaitForExit();
Console.WriteLine("Application installed successfully!");
return true; //Return True if process ended successfully
}
catch
{
Console.WriteLine("There was a problem installing the application!");
return false; //Return False if process ended unsuccessfully
}
}
public static bool RunUninstallMSI(string guid)
{
try
{
Console.WriteLine("Starting to uninstall application");
ProcessStartInfo startInfo = new ProcessStartInfo("cmd.exe", string.Format("/c start /MIN /wait msiexec.exe /x {0} /quiet", guid));
startInfo.WindowStyle = ProcessWindowStyle.Hidden;
Process process = Process.Start(startInfo);
process.WaitForExit();
Console.WriteLine("Application uninstalled successfully!");
return true; //Return True if process ended successfully
}
catch
{
Console.WriteLine("There was a problem uninstalling the application!");
return false; //Return False if process ended unsuccessfully
}
}
This works for me.
Process process = new Process();
process.StartInfo.FileName = # "C:\PATH\Setup.exe";
process.StartInfo.Arguments = "/quiet";
process.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
process.Start();
process.WaitForExit();
Have you tried using the /Q or /QB parameter that is listed in the Installation parameters? It might look something like this:
p.StartInfo.Arguments = "/Q";
I got that out of this document: http://msdn.microsoft.com/en-us/library/ms144259(v=sql.100).aspx
Here is my logic to silent install an app for all users:
public void Install(string filePath)
{
try
{
Process process = new Process();
{
process.StartInfo.FileName = filePath;
process.StartInfo.Arguments = " /qb ALLUSERS=1";
process.EnableRaisingEvents = true;
process.Exited += process_Exited;
process.Start();
process.WaitForExit();
}
}
catch (InvalidOperationException iex)
{
Interaction.MsgBox(iex.Message, MsgBoxStyle.OkOnly, MethodBase.GetCurrentMethod().Name);
}
catch (Exception ex)
{
Interaction.MsgBox(ex.Message, MsgBoxStyle.OkOnly, MethodBase.GetCurrentMethod().Name);
}
}
private void process_Exited(object sender, EventArgs e)
{
var myProcess = (Process)sender;
if (myProcess.ExitCode == 0)
// do yours here...
}
string filePath = #"C:\Temp\Something.msi";
Process.Start(filePath, #"/quiet").WaitForExit();
It worked for me.