I'm calling Process.Start, but it blocks the current thread.
pInfo = new ProcessStartInfo("C:\\Windows\\notepad.exe");
// Start process
mProcess = new Process();
mProcess.StartInfo = pInfo;
if (mProcess.Start() == false) {
Trace.TraceError("Unable to run process {0}.");
}
Even when the process is closed, the code doesn't respond anymore.
But Process.Start is really supposed to block? What's going on?
(The process start correctly)
using System;
using System.Diagnostics;
using System.Threading;
using System.Windows.Forms;
namespace Test
{
class Test
{
[STAThread]
public static void Main()
{
Thread ServerThread = new Thread(AccepterThread);
ServerThread.Start();
Console.WriteLine (" --- Press ENTER to stop service ---");
while (Console.Read() < 0) { Application.DoEvents(); }
Console.WriteLine("Done.");
}
public static void AccepterThread(object data)
{
bool accepted = false;
while (true) {
if (accepted == false) {
Thread hThread = new Thread(HandlerThread);
accepted = true;
hThread.Start();
} else
Thread.Sleep(100);
}
}
public static void HandlerThread(object data)
{
ProcessStartInfo pInfo = new ProcessStartInfo("C:\\Windows\\notepad.exe");
Console.WriteLine("Starting process.");
// Start process
Process mProcess = new Process();
mProcess.StartInfo = pInfo;
if (mProcess.Start() == false) {
Console.WriteLine("Unable to run process.");
}
Console.WriteLine("Still living...");
}
}
}
Console output is:
--- Press ENTER to stop service ---
Starting process.
Found it:
[STAThread]
Makes the Process.Start blocking. I read STAThread and Multithreading, but I cannot link the concepts with Process.Start behavior.
AFAIK, STAThread is required by Windows.Form. How to workaround this problem when using Windows.Form?
News for the hell:
If I rebuild my application, the first time I run application work correctly, but if I stop debugging and restart iy again, the problem araise.
The problem is not raised when application is executed without the debugger.
No, Process.Start doesn't wait for the child process to complete... otherwise you wouldn't be able to use features like redirected I/O.
Sample console app:
using System;
using System.Diagnostics;
public class Test
{
static void Main()
{
Process p = new Process {
StartInfo = new ProcessStartInfo("C:\\Windows\\notepad.exe")
};
p.Start();
Console.WriteLine("See, I'm still running");
}
}
This prints "See, I'm still running" with no problems on my box - what's it doing on your box?
Create a ProcessStartInfo and set UseShellExecute to false (default value is true). Your code should read:
pInfo = new ProcessStartInfo("C:\\Windows\\notepad.exe");
pInfo.UseShellExecute = false;
// Start process
mProcess = new Process();
mProcess.StartInfo = pInfo;
if (mProcess.Start() == false) {
Trace.TraceError("Unable to run process {0}.");
}
I had the same issue and starting the executable creating the process directly from the executable file solved the issue.
I was experiencing the same blocking behavior as the original poster in a WinForms app, so I created the console app below to simplify testing this behavior.
Jon Skeet's example uses Notepad, which only takes a few milliseconds to load normally, so a thread block may go unnoticed. I was trying to launch Excel which usually takes a lot longer.
using System;
using System.Diagnostics;
using static System.Console;
using System.Threading;
class Program {
static void Main(string[] args) {
WriteLine("About to start process...");
//Toggle which method is commented out:
//StartWithPath(); //Blocking
//StartWithInfo(); //Blocking
StartInNewThread(); //Not blocking
WriteLine("Process started!");
Read();
}
static void StartWithPath() {
Process.Start(TestPath);
}
static void StartWithInfo() {
var p = new Process { StartInfo = new ProcessStartInfo(TestPath) };
p.Start();
}
static void StartInNewThread() {
var t = new Thread(() => StartWithPath());
t.Start();
}
static string TestPath =
Environment.GetFolderPath(Environment.SpecialFolder.Desktop) +
"\\test.xlsx";
}
Calls to both StartWithPath and StartWithInfo block my thread in a console app. My console does not display "Process Started" until after the Excel splash screen closes and the main window is open.
StartInNewThread will display both messages on the console immediately, while the splash screen for Excel is still open.
We had this problem when launching a .bat script that was on a network drive on a different domain (we have dual trusted domains). I ran a remote C# debugger and sure enough Process.Start() was blocking indefinitely.
When repeating this task interactively in power shell, a security dialog was popping up:
As far as a solution, this was the direction we went. The person that did the work modified domain GPO to accomplish the trust.
Start server via command prompt:
"C:\Program Files (x86)\IIS Express\iisexpress" /path:\Publish /port:8080
This take access to sub-threads of the tree process of OS.
If you want to launch process and then make the process independent on the "launcher" / the originating call:
//Calling process
using (System.Diagnostics.Process ps = new System.Diagnostics.Process())
{
try
{
ps.StartInfo.WorkingDirectory = #"C:\Apps";
ps.StartInfo.FileName = #"C:\Program Files\Microsoft Office\Office14\MSACCESS.EXE"; //command
ps.StartInfo.Arguments = #"C:\Apps\xyz.accdb"; //argument
ps.StartInfo.UseShellExecute = false;
ps.StartInfo.RedirectStandardOutput = false;
ps.StartInfo.WindowStyle = System.Diagnostics.ProcessWindowStyle.Maximized;
ps.StartInfo.CreateNoWindow = false; //display a windows
ps.Start();
}
catch (Exception ex)
{
MessageBox.Show(string.Format("==> Process error <=={0}" + ex.ToString(), Environment.NewLine));
}
}
Related
Im trying to build a cmd.exe wrapper but i cant figure out how to wait for a process inside the cmd process to finish.
When im run ping.exe in my program, my "inputline" (the path) will output to the console before the ping-command is finished.
I cant use: .WaitForInputIdle(); because I don't have a GUI. "This could be because the process does not have a graphical interface."
Is it even possible to solve or is there any better way to do it?
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace ObjectTest
{
class cmd
{
Process cmdProcess;
StreamWriter cmdStreamWriter;
public cmd()
{
//WinAPI.ShowConsoleWindow();
Process();
//WinAPI.HideConsoleWindow();
}
private void Process()
{
StartCmd();
string command = "";
while (command != "exit")
{
Thread.Sleep(100);
cmdProcess.WaitForInputIdle();
Console.Write(Environment.NewLine + Directory.GetCurrentDirectory() + "> ");
command = Console.ReadLine();
SendCommand(command);
}
}
private void StartCmd()
{
cmdProcess = new Process();
cmdProcess.StartInfo.FileName = "cmd.exe";
cmdProcess.StartInfo.UseShellExecute = false;
cmdProcess.StartInfo.CreateNoWindow = true;
cmdProcess.StartInfo.RedirectStandardOutput = true;
cmdProcess.OutputDataReceived += new DataReceivedEventHandler(SortOutputHandler);
cmdProcess.ErrorDataReceived += new DataReceivedEventHandler(SortOutputHandler);
cmdProcess.StartInfo.RedirectStandardInput = true;
cmdProcess.Start();
cmdStreamWriter = cmdProcess.StandardInput;
cmdProcess.BeginOutputReadLine();
}
private void SendCommand(string command)
{
cmdStreamWriter.WriteLine(command);
}
private void btnQuit_Click(object sender, EventArgs e)
{
cmdStreamWriter.Close();
cmdProcess.WaitForExit();
cmdProcess.Close();
}
private static void SortOutputHandler(object sendingProcess, DataReceivedEventArgs outLine)
{
if (!string.IsNullOrEmpty(outLine.Data))
{
Console.WriteLine(outLine.Data);
}
}
}
}
If it's only actual processes you want to catch you can use polling methods as such:
Before running the command, collect all existing processes of, for example, ping (.exe), using Process.GetProcessesByName, and store their PIDs.
Run the command
In order to wait for exit, Again scan for all ping processes, and wait on all processes that did not previously exist.
Note that this will fail, or at least not be accurate, if another process will launch another ping between steps 1 and 3.
You should also keep in mind that CMD does not wait on all type of processes, only those which are defined as console applications (see this question).
When starting a process, you can specify that you want to wait:
var process = Process.Start(...);
process.WaitForExit();
Here's a link to MSDN explaining it: http://msdn.microsoft.com/en-us/library/fb4aw7b8(v=vs.110).aspx
I think this is wat you need.
Anybody knows how I could make a Monitor program in C# to control that an application will always be running? That I need it's a double monitor application, I will explain: I have a application Ap1 that have to control that Ap2 process it's always started, and Ap2 have to control that Ap1 process it's always started. In resume, if I kill Ap1 process the Ap2 application should start Ap1 immediatelly (and vice versa if Ap2 die).
This the code that I'm developing but didn't work, I don't know but when I kill the program monitored no started again.
public void Monitor()
{
Console.WriteLine("Monitoring {0} process...", processname);
while (IsProcessRunning() == true)
{
Process[] runningNow = Process.GetProcesses();
foreach (Process process in runningNow)
{
if (process.ProcessName == processname)
{
System.Threading.Thread.Sleep(1000);
Console.WriteLine("Process:{0} is running actually", process.ProcessName);
}
else { /* Provide a messagebox. */ }
}
// Sleep till the next loop
Thread.Sleep(intInterval);
}
while (IsProcessRunning() != true)
{
ProcessMonitor proc = new ProcessMonitor("ConsoleApplication1", 1000);//Check if is running each 1 second
Console.WriteLine("Process:{0} is NOT running actually", processname);
//Application folder of exe
String applicationFolder = "C:\\App";
//Get the executable file
String procPath = applicationFolder + #"\Ap1.exe";
Console.WriteLine("Running {0} process...", proc.Name);
//Lauch process
Process p = Process.Start(procPath);
Console.WriteLine("Process running {0} OK", proc.Name);
//p.WaitForExit(10000);
}
}
And the main program:
static void Main(string[] args)
{
ProcessMonitor proc = new ProcessMonitor("ConsoleApplication1", 1000);//Check if is running each 1 second
if (proc.IsProcessRunning() != true)
{
Console.WriteLine("{0} is not running.", proc.Name);
//Application folder of exe
String applicationFolder = "C:\\App";
//Get the executable file
String procPath = applicationFolder + #"\Ap1.exe";
Console.WriteLine("Running {0} process...", proc.Name);
//Lauch process
Process p = Process.Start(procPath);
Console.WriteLine("Process running {0} OK", proc.Name);
//p.WaitForExit(10000);
}
else
{
proc.Monitor();
}
proc.FreezeOnScreen();
}
You could set up a task in the task scheduler that launches your program at a set interval (say every half hour). I believe you can set it to not start the task if there is already an instance running. (Correct me if I am wrong)
We needed this once and simply monitored the process list periodically, checking for the name of the process. If the process wasn't present for a given amount of time, we restarted it. You can use Process.GetProcessesByName.
I have got a problem with my C# project. I got there 2 applications:
Executor application which I will call Mini Launcher
Executed application which I will call Launcher
My problem is: I want to run my Launcher by Mini launcher and in on Show event of Launcher app close Mini Launcher.
My Mini Launcher is something like splash screen but with additional functionality like upgrade Launcher, and other. Its my execution code:
ProcessStartInfo startInfo = new ProcessStartInfo();
startInfo.WorkingDirectory = "My Directory"
startInfo.FileName = "My App";
try
{
using (Process exeProcess = Process.Start(startInfo))
{
exeProcess.();
}
}
catch
{
...
}
Have a look at the Mutex class. Named mutices provide a way for applications to send signals to one another.
The following sample shows two Console-applications. The TestMutexLauncher-application launches the TestMutex application:
using System;
using System.Diagnostics;
using System.Threading;
namespace TestMutexLauncher
{
class Program
{
static void Main(string[] args)
{
var p = Process.Start("TestMutex");
Console.WriteLine("Waiting for other process to release the mutex.");
Thread.Sleep(1000); // maybe p.WaitForInputIdle is an alternative for WinForms/WPF
Mutex mutex = null;
for (int i = 0; i < 100; i++)
{
if (Mutex.TryOpenExisting("MyUniqueMutexName", out mutex))
break;
Thread.Sleep(100);
}
if (mutex != null)
{
try
{
mutex.WaitOne();
mutex.ReleaseMutex();
}
finally
{
mutex.Dispose();
}
}
}
}
}
The launcher application starts the process and waits for a Mutex to be created in the other process. If it can acquire ownership of the the Mutex in a specified time frame, it waits to get ownership of the Mutex. After that, it realeases and disposes the Mutex.
The first task of the launched application is to create the Mutex, do the initialization actions and then release the Mutex.
using System;
using System.Threading;
namespace TestMutex
{
class Program
{
static void Main(string[] args)
{
using (var mutex = new Mutex(true, "MyUniqueMutexName"))
{
// Do something
for (int i = 0; i < 10000; i++)
Console.Write(".");
Console.WriteLine();
Console.WriteLine("Press enter...");
Console.ReadLine();
mutex.ReleaseMutex();
}
for (int i = 0; i < 10000; i++)
Console.Write(".");
Console.WriteLine();
Console.WriteLine("Press enter...");
Console.ReadLine();
}
}
}
Firstly, I would recommend you consider:
1) Do they actually need to be separate applications?
2) If so, why can't MiniLauncher just close itself after Launcher has loaded?
But if you have to do it this way, then the code you're looking for is something like this:
private void OnShow()
{
var target = Process.GetProcessesByName("MiniLauncher.exe").FirstOrDefault();
if (target != null)
{
// any other checks that this is indeed the process you're looking for
target.Close();
}
}
you can call another project executable from current running project and then you can close your application.
class Program
{
static void Main()
{
//
// Open the application "application" that is in the same directory as
// your .exe file you are running.
//
Process.Start("example.txt");
// or for another directory you need to specify full path
Process.Start("C:\\");
}
}
I am starting an executable using this code:
Process proc = new Process();
proc.StartInfo.FileName = executablePath;
proc.Start();
proc.WaitForInputIdle();
after this calling proc.Id it gives me some integer, which is not real process ID. In the task manager there is another ID for this process and also I am using MS UI Automation to access this application, which also returns the same ID as in task manager. So my question is how can I get the real process ID of started process?
UPDATE
I found out that on Windows 7 it works fine and returns me the right ID, but not on Windows XP. What can be the reason?
SCENARIO
The scenario of the application is the following. I have a running embedded HTTP server, which is implemented not by me, (here is the source). The client connects to the web server and sends a request to run a program. In the request handler of my server I am just using Process.start() to start the requested application. As a web server the program creates threads for every client session connected to it (I assume so, as I didn't wrote it). Can this somehow help to identify the problem as it exists only on Windows XP X86 Service Pack 3?
An example of how I did it:
bool started = false;
var p = new Process();
p.StartInfo.FileName = "notepad.exe";
started = p.Start();
try {
var procId = p.Id;
Console.WriteLine("ID: " + procId);
}
catch(InvalidOperationException)
{
started = false;
}
catch(Exception ex)
{
started = false;
}
Otherwise, try using handles like this:
Using handlers
Getting handler
hWnd = (int) process.MainWindowHandle;
int processId;
GetWindowThreadProcessId(hWnd, out processId);
[DllImport("user32")]
static extern int GetWindowThreadProcessId(IntPtr hWnd, out int processId);
Side note:
What happens if you get the array of process and iterate over them and compare the PIDs?
Process[] p = Process.GetProcessesByName( "testprogram" );
foreach(var proc in p)
Console.WriteLine("Found: "+proc.Id == myExpectedProcId);
This:
using (Process process = Process.Start("notepad.exe"))
{
process.WaitForInputIdle();
Console.WriteLine(process.Id);
}
Actually works for me:
http://pasteboard.s3.amazonaws.com/images/1350293463417532.png
Task Manager:
http://pasteboard.s3.amazonaws.com/images/1350293536498959.png
My thoughts:
Actually your process starts another process and you are trying to get ID of some kind of launcher. (It can start itself by the way).
Below also returns the PID of a process
Process[] p = Process.GetProcessesByName("YourProcessName");
Now you can get process Id by using p[i].Id;
I'm just trying to guess here, since it's difficult to understand what's really happening without seeing the real code. Anyway, you mentioned Trhreads in one of your comment. Is it possible that you have a single variable proc of type Process which is initialized in your main thread, and then the process is started in a different Thread?
If this is the case, maybe the process is started more than once, and you get the PID of just one of them. The only way I was able to reproduce your case is this one:
private Process proc;
private List<int> pids = new List<int>();
public void StartProc()
{
// this tries to simulate what you're doing. Starts the process, then
// wait to be sure that the second process starts, then kill proc
proc.Start();
pids.Add(proc.Id);
Thread.Sleep(300);
try
{
proc.Kill();
}
catch {}
}
// the method returns the PID of the process
public int Test()
{
proc = new Process();
proc.StartInfo.FileName = #"notepad.exe";
for (int i = 0; i < 2; i++)
{
Thread t = new Thread(StartProc);
t.Start();
Thread.Sleep(200);
}
Thread.Sleep(500);
return proc.Id;
}
When you executes Test, you should see a single active Notepad, and the PID returned by the method is different by the one showed by the Task Manager. But if you take a look at the pids List, you should see that the Task Manager PID is the first element in the list, and the one returned by the method is the second one.
Is it possible that you have done something similar?
Long story short, it's about a Windows Form Application with a WebBrowser control. The application opens a website, fills in username and password, logs in, launches a vpn client (exe) by executing a javascript. Once the vpn client is successfully started, the application should exit. The first half is working fine.
I'd like to check if the vpn client is running, if so, it should close the my application, otherwise wait for the exe to start.
private void LaunchJS()
{
HtmlDocument doc = webBrowser1.Document;
Object js = doc.InvokeScript("launchJS");
label1.Text = "complete";
}
.
if (label1.Text == ("complete"))
{
bool prc = false;
while (!prc)
{
foreach (Process clsProcess in Process.GetProcesses())
{
if (clsProcess.ProcessName.Contains("JS_plugin"))
{
prc = true;
Application.Exit();
}
}
}
}
The Problem I'm experiencing is that the javascript launch is unsuccessful, when I enable the second part (check process) of the code. The java script isn't executed, the program will never launch and the check process goes into an infinite loop.
Any help would be much appreciated!
doing the process check in a separate thread has resolved my issue.
private void GetPRo()
{
if (label1.Text == ("complete"))
{
bool prc = false;
while (!prc)
{
foreach (Process clsProcess in Process.GetProcesses())
{
if (clsProcess.ProcessName.Contains("JS_plugin"))
{
prc = true;
Application.Exit();
}
}
}
}
}
.
Thread CloseApp = new Thread(new ThreadStart(GetPro));
CloseApp.Start();