I have the following function:
public static void ExecuteNewProcess(string fileToExecute, Action<string> writeToConsole)
{
ProcessStartInfo startInfo = new ProcessStartInfo(fileToExecute);
Process processToExecute = new Process();
startInfo.UseShellExecute = true;
processToExecute.StartInfo = startInfo;
if (!File.Exists(fileToExecute))
{
throw new FileNotFoundException("File not found for execution");
}
if (processToExecute.Start())
{
Thread.Sleep(6000);
Process[] procs = Process.GetProcesses();
if (IsProcessOpen(Path.GetFileNameWithoutExtension(fileToExecute)))
{
writeToConsole(fileToExecute + " launched successfully...");
}
else
{
writeToConsole(fileToExecute + " started but not found.");
throw new Exception("Application started butnot found running...Delay = 6000, File Name = " + Path.GetFileNameWithoutExtension(fileToExecute));
}
}
else
{
writeToConsole("Error Launching application: " + fileToExecute);
throw new Exception("Application did not launch " + fileToExecute);
}
}
private static bool IsProcessOpen(string name)
{
foreach (Process clsProcess in Process.GetProcesses())
{
if (clsProcess.ProcessName.Contains(name))
{
return true;
}
}
return false;
}
So the problem is that sometimes my application that I am trying to start with this function is not starting (It starts about 80% of the time). However I do go through the part of the code that checks to make sure it started and outputs as such. I am not sure why it is not starting. I double click the application when I see it doesnt start to make sure its a valid exe. It always is and starts fine. I have also tried using the shell and not using the shell. No difference.
I am thinking that processToExecute is getting cleaned up before the application has successfully started all the way. Just a guess though.
I appreciate your help in advance.
I put in a few sleeps to see if it was just happening too fast.
The reason 20% of time your application don't show up when started by Process because of the time the application takes load before we see the user Interface
So their are two ways through which you might be able to achieve it
1. start the process - > process.Start(); And then process.WaitForInputIdle();
OR
2. start the process - > process.Start(); And then Thread.Sleep(1000);
//make sure you give reasonable milliseconds
Related
I'm currently in the process of creating a console application that acts as a Video Management Hub. I'm having issues with passing arguments into command line through process. Every time it returns the output from stdout and stderror using appropriate threads for each it's acting as though the Standard.Error.ReadToEnd() and Standard.Out.ReadToEnd() aren't seeing the full arguments after it's waited for the process to exit. Exception returns "is not recognized as an internal or external command, operable program or batch file." Code snippets below show Open method process.
private void Thread_ReadStandardError()
{
if (activeProcess != null)
{
stdErr = activeProcess.StandardError.ReadToEnd();
}
}
private void Thread_ReadStandardOut()
{
if (activeProcess != null)
{
stdOut = activeProcess.StandardOutput.ReadToEnd();
}
}
private string Open(string cmd)
{
string args = "/C [command]";
string temp_path = args.Replace("[command]",cmd);
this.pStartInfo.FileName = "cmd.exe";
this.pStartInfo.Arguments = "\"" + temp_path + "\"";
this.activeProcess.StartInfo = pStartInfo;
this.pStartInfo.CreateNoWindow = true;
this.pStartInfo.UseShellExecute = false;
this.pStartInfo.RedirectStandardOutput = true;
this.pStartInfo.RedirectStandardError = true;
activeProcess = Process.Start(pStartInfo);
Thread thread_ReadStandardError = new Thread(new ThreadStart(Thread_ReadStandardError));
Thread thread_ReadStandardOut = new Thread(new ThreadStart(Thread_ReadStandardOut));
if (pStartInfo.RedirectStandardError)
{
thread_ReadStandardError.Start();
}
if (pStartInfo.RedirectStandardOutput)
{
thread_ReadStandardOut.Start();
}
activeProcess.WaitForExit();
thread_ReadStandardError.Join();
thread_ReadStandardOut.Join();
string output = stdOut + stdErr;
return output;
}
Ultimately I am trying to use a modified version of ExifToolWrapper to run command line arguments to read in video Metadata. I got appropriate arguments/paths prior to my 'Open' method and handle white space before passing in arguments. Process is relatively new to me and prior I was trying to use EnvironmentalVariables to pass in arguments and I get the same output from stdOut+stdErr of
"C:Users###....is not recognized as an internal or external command..."
Is it possibly the way in which my process in setup?
I'm writing a software and trying to implement an automatic updater into it as a separate application. I have both the software itself and the updater under the same solution.
When an update is available from a server, my program prompts the user to update, this part works.
I fail to call the updater app and then exit only the first program.
This is what I have not:
private void button2_Click(object sender, EventArgs e)
{
// Update
ExecuteAsAdmin("AutoUpdater.exe");
//System.Windows.Forms.Application.Exit();
Process.GetCurrentProcess().Kill();
}
public void ExecuteAsAdmin(string fileName)
{
Process proc = new Process();
proc.StartInfo.FileName = fileName;
proc.StartInfo.UseShellExecute = true;
proc.StartInfo.Verb = "runas";
proc.Start();
}
This does successfully start the AutoUpdater.exe but then exists both, the first program and the AutoUpdater.exe, latter should not be exited as that should do the updating.
How to exit only one program from the same solution?
Add the code to shut down the main app in to the updater. You know the process name so it should be fairly easy. This way you can also check that the updater actually starts running before the main app is shut down.
Code below is borrowed from this answer: https://stackoverflow.com/a/49245781/3279876 and I haven't tested it my self.
Process[] runningProcesses = Process.GetProcesses();
foreach (Process process in runningProcesses)
{
// now check the modules of the process
foreach (ProcessModule module in process.Modules)
{
if (module.FileName.Equals("MyProcess.exe"))
{
process.Kill();
} else
{
enter code here if process not found
}
}
}
This works with a minimal winforms application in my system:
System.Diagnostics.Process p = System.Diagnostics.Process.Start("notepad.exe");
Application.Exit();
but also this:
ExecuteAsAdmin("notepad.exe");
Application.Exit()
My program prints silently via the PDF reader Foxit Reader in a new process.
On occasion, my program attempts to print two PDFs at the same time, which causes one of them to fail to print.
Here is my code:
string filename = "file.pdf";
string fileDir1 = #"C:\Program Files (x86)\Foxit Software\Foxit Reader\FoxitReader.exe";
Process pdfProcess = new Process();
pdfProcess.StartInfo.FileName = fileDir1;
pdfProcess.StartInfo.Arguments = string.Format(#"/t {0} {1}", filename ,"pos-80");
pdfProcess.StartInfo.CreateNoWindow = true;
pdfProcess.StartInfo.WorkingDirectory = Path.GetDirectoryName(fileDir1);
pdfProcess.Start();
if (!pdfProcess.WaitForExit(2500))
{
pdfProcess.Kill();
}
Please help me resolve this issue.
Make sure you have Foxit open.
using System.Diagnostics;
List<Process> Processlist = Process.GetProcesses().ToList();
This gives you a list of currently running processes.
foreach(Process p in Processlist)
{
Console.WriteLine("Process " + p.Id + " is named '" + p.ProcessName + "'");
}
When running the above code, you should see the name of the Foxit process in your output window.
Alternatively, put a break-point on the foreach line and hover over the list to see all the names that way.
bool IsFoxitProcessRunning = false;
foreach(Process p in Processlist)
{
if(p.ProcessName == "Foxit process name here") //Replace with the name of the foxit process
{
IsFoxitProcessRunning = true;
}
}
Now, only start a new Foxit process if one isn't already running.
if(!IsFoxitProcessRunning)
{
//insert code to run next foxit process here.
}
Notes:
You may need to implement a queue to keep track of pdfs waiting to run.
You may also wish to alert IT support if a Foxit is waiting more 5 or 10 mins to run.
You could choose to make Processlist a class attribute, and periodically refresh Processlist using a Timer, by calling Processlist = Process.GetProcesses().ToList(); on the Tick event. every 30 seconds or so while a PDF is waiting to be printed.
I am trying to reach one simple requirement. I would like to create a C# library that talks to the git executable. I am writing a version control tool for my team that will allow access to git commands for non tech-savvy individuals. Unfortunately, I can not use any third party DLL's (I am using Unity and I do not want to push the requirement for Unity pro due to plugins), otherwise I would use GitSharp or something along those lines.
Currently, I have a function called RunGitCommand that is meant to do all my bidding. This snippet is as follows:
private void RunGitCommand(string executablePath, string arguments, int maxCommandDurationMilliseconds)
{
using (AutoResetEvent outputWaitHandle = new AutoResetEvent(false))
using (AutoResetEvent errorWaitHandle = new AutoResetEvent(false))
{
try
{
CommandOutput = string.Empty;
CommandError = string.Empty;
ProcessStartInfo processStartInfo = new ProcessStartInfo();
processStartInfo.CreateNoWindow = true;
processStartInfo.FileName = executablePath;
processStartInfo.Arguments = arguments;
processStartInfo.UseShellExecute = false;
processStartInfo.RedirectStandardError = true;
processStartInfo.RedirectStandardOutput = true;
int processedTime = 0;
using (Process process = new Process())
{
StringBuilder outputData = new StringBuilder();
StringBuilder errorData = new StringBuilder();
process.StartInfo = processStartInfo;
process.OutputDataReceived += (sender, e) => {
outputWaitHandle.Set();
if (e.Data == null)
{
//outputWaitHandle.Set();
}
else
{
outputData.AppendLine(e.Data);
}
};
process.ErrorDataReceived += (sender, e) =>
{
errorWaitHandle.Set();
if (e.Data == null)
{
//errorWaitHandle.Set();
}
else
{
errorData.AppendLine(e.Data);
}
};
process.Start();
if(process.Id == 0)
{
Environment.LogError("Process id is 0. Aborting.");
return;
}
RunningProcessDescriptor processDescriptor = new RunningProcessDescriptor(maxCommandDurationMilliseconds, process.Id);
ProcessIds.Add(processDescriptor);
Thread.Sleep(200);
int newMaxTime = maxCommandDurationMilliseconds - 100;
process.BeginOutputReadLine();
process.BeginErrorReadLine();
if (process.WaitForExit(newMaxTime) && outputWaitHandle.WaitOne(newMaxTime) && errorWaitHandle.WaitOne(newMaxTime))
{
process.CancelOutputRead();
process.CancelErrorRead();
CommandOutput = outputData.ToString();
CommandError = errorData.ToString();
string combinedOutput = string.Join(System.Environment.NewLine, new string[]{ CommandError, CommandOutput }).Trim();
BatchOutput = string.Join(System.Environment.NewLine, new string[]{ BatchOutput, string.Format("----------// {0} {1} //----------", executablePath, arguments), CommandOutput }).Trim();
BatchError = string.Join(System.Environment.NewLine, new string[]{ BatchError, string.Format("----------// {0} {1} //----------", executablePath, arguments), CommandError }).Trim();
InterpretErrorsAndAddToLists(combinedOutput);
}
else
{
process.Close();
process.WaitForExit();
}
ProcessIds.Remove(processDescriptor);
}
}
catch(Exception genericException)
{
Environment.LogError(genericException.Message);
Environment.LogError(genericException.StackTrace);
}
}
}
Another thing to note is that I'm using this to run these commands so that they don't execute on the main thread:
ThreadPool.QueueUserWorkItem
As you should be able to identify by my commenting and layout, this function is the result of hours of troubleshooting and I am willing to try anything at this point to make it work. I've already moved to using asynchronous calls for receiving the output/error streams, and even added AutoResetEvent objects to cause my threads to wait for each other (although I am not completely familiar with them and might be doing something wrong).
No matter what I try, it seems to randomly hang and not allow the process to exit. When I manually kill the git process, the output is spit out (and is usually right) and the process exits and everything works as normal.
I'm at the point in troubleshooting and frustration where I need professional input. Here are my questions:
Is there something blatantly or obviously wrong with my code below? If I'm doing it wrong, please advise me how to properly execute this code.
Is there another solution where I do not need to include third party DLL files and can just use raw .NET to grab the git console process and interact with it (on mac and pc)?
Other alternatives to these approaches, such as one i've been considering, that uses a "client/server" architecture. I can use third party dll's and whatnot in a separate downloadable program that communicates to the git plugin via TCP to send and receive output/input to the git process. This one is much more work, but would potentially take less time than troubleshooting the git only version.
Just let me know what your professional opinions are so that I can rest at night :).
I look forward to talking with everyone!
-Zack
I tend to use a very simple piece of code for executing a non-interactive command, and getting the standard output from the result. I would suggest starting from something like this, and checking it doesn't hang. Then build any additional logic from there.
private static string ExecuteCommand(string command, string arguments)
{
command = System.Environment.ExpandEnvironmentVariables(command);
var process = new Process
{
StartInfo =
{
UseShellExecute = false,
RedirectStandardOutput = true,
RedirectStandardError = true,
CreateNoWindow = true,
FileName = command,
Arguments = arguments
}
};
process.Start();
process.WaitForExit();
return process.StandardOutput.ReadToEnd();
}
It's often hard to isolate the problem when there's so much 'dead wood' in the code. Strip it back to the bare bones, and see if you can isolate the problem from there.
I am developing a Windows Forms application in which I need to edit certain config files. Now when the user clicks on the edit option, I want to launch these config files in a simple notepad editor. Once launched I want to stall my application. Only when the user closes the notepad editor, I want to un-stall my application. How can this be done ?
I have seen these questions, but the answers have many issues. (I read the comments given there.)
Q1Q2
You can use the Exited-Event:
try
{
Process myProcess = new Process();
myProcess.StartInfo.FileName = "notepad.exe";
myProcess.StartInfo.Arguments = #"C:\PathToYourFile";
myProcess.EnableRaisingEvents = true;
myProcess.Exited += new EventHandler(myProcess_Exited);
myProcess.Start();
}
catch (Exception ex)
{
//Handle ERROR
return;
}
// Handle Exited event and display process information.
private void myProcess_Exited(object sender, System.EventArgs e)
{
eventHandled = true;
Console.WriteLine("Exit time: {0}\r\n" +
"Exit code: {1}\r\nElapsed time: {2}", myProcess.ExitTime, myProcess.ExitCode, elapsedTime);
}
var process = System.Diagnostics.Process.Start("yourfile.txt");
process.WaitForExit();
This will open your file. However, sometimes the process will be null and you will not be able to wait for exit. Why?
Process.Start Method
Return Value Type: System.Diagnostics.Process
A new Process component
that is associated with the process resource, or null if no process
resource is started (for example, if an existing process is reused).
http://msdn.microsoft.com/en-us/library/53ezey2s.aspx
You can initiate a Process and WaitForExit:
Process pr = Process.Start("Notepad");
pr.WaitForExit();