c# wait until dialog of started process closes - c#

How do I wait (block) my program until a specific dialog of my previous started process closes?
I'm starting pageant.exe to load a ssh key. Pageant is started with the class "Process". This works fine.
My ssh key has a passphrase. So my main program/process (this one started the process) has to wait until the user entered the ssh key passphrase.
I got an idea how to wait, but don't know how to do this in c#:
If pageant ask for the passphrase a dialog appears. So my main program/process can wait until the passphrase dialog is closed. Is it possible to do this in c#?
I got the idea from here.
EDIT: found a solution
// wait till passphrase dialog closes
if(WaitForProcessWindow(cPageantWindowName))
{ // if dialog / process existed check if passphrase was correct
do
{ // if passphrase is wrong, the passphrase dialog is reopened
Thread.Sleep(1000); // wait till correct passphrase is entered
} while (WaitForProcessWindow(cPageantWindowName));
}
}
private static bool WaitForProcessWindow(string pProcessWindowName)
{
Process ProcessWindow = null;
Process[] ProcessList;
bool ProcessExists = false; // false is returned if process is never found
do
{
ProcessList = Process.GetProcesses();
ProcessWindow = null;
foreach (Process Process in ProcessList)
{ // check all running processes with a main window title
if (!String.IsNullOrEmpty(Process.MainWindowTitle))
{
if (Process.MainWindowTitle.Contains(pProcessWindowName))
{
ProcessWindow = Process;
ProcessExists = true;
}
}
}
Thread.Sleep(100); // save cpu
} while (ProcessWindow != null); // loop as long as this window is found
return ProcessExists;
}

This might help you out, but doesn't give you entire control. I am not familiar with pageant, so I am not sure if it keeps running in the background or not. But in case the program automatically closes you could do this in your application.
So you could check in a loop if the Pageant application is open or not, once it is open you execute some code and once it is closed you enable the program again.
Execute this code in some background worker.
//Lets look from here if pageant is open or not.
while(true)
{
if (Process.GetProcessesByName("pageant").Length >= 1)
{
//block your controls or whatsoever.
break;
}
}
//pageant is open
while(true)
{
if (!Process.GetProcessesByName("pageant").Length >= 1)
{
//enable controls again
break;
}
}
//close thread

Related

Cannot read STDOut from Process that is running in background

So, under Linux I have to connect to a bluetooth device via the command rfcomm connect hci0 xx:xx:xx:xx:xx:xx, which starts a bluetooth connection, but has to remain running in order to stay connected.
I have to write everything as an .NET Core Program
Running the command outputs the following lines after a few seconds:
Connected /dev/rfcomm0 to xx:xx:xx:xx:xx:xx on channel 1
Press CTRL-C for hangup
From that Output I have to get the /dev/rfcomm0 part, so I can read it with a SerialPortReader, and if something goes wrong, like, let's say there is no more data incoming, I have to kill the process and start anew, until I have a good connection.
Now my logic is something like this:
while(!Terminate)
{
string port = Connect();
ReadData(port);
BTProcess.Kill();
}
Don't bother with the ReadData(port); function, as my program never even comes near that.
The Connect() looks something like this:
while (!Connected)
{
Console.WriteLine("Configuring Process");
BTProcess = new Process();
BTProcess.StartInfo.FileName = "rfcomm";
BTProcess.StartInfo.Arguments = "connect hci0 xx:xx:xx:xx:xx:xx"
BTProcess.StartInfo.RedirectStandardOutput = true;
BTProcess.StartInfo.UseShellExecute = false;
Console.WriteLine("Starting Process");
BTProcess.Start();
StreamReader reader = _BTProcess.StandardOutput;
bool done = false;
Console.WriteLine("Reading STDOUT now.");
while (!done) // EDIT: If I do the while with !reader.EndOfStream then it won't even enter into the loop
{
Console.Write("-");
int c = reader.Read(); // Program stops in this line
if(c != -1)
{
port += (char)c;
}
Console.Write(c);
if (c == 0)
{
port = "";
done = true;
_BTProcess.Kill();
}
if (/* String Contains Logic blabla */)
{
port = /* The /dev/rfcomm0 stuff */
Connected = true;
done = true;
}
}
reader.Close();
}
return port;
I did check already if the Output isn't redirected to like STDErr or something, but no, it is 100% written in STDOut.
I have already tried a logic with like an EventHandler that handles StandardOutput Events, and a logic where I read it asynchronously, but both with no success. All had the same problem, they all block at the Read(); function. My guess is that maybe the internal buffer doesn't get flushed correctly.
Maybe someone here knows an answer to my problem.
P.S.: I know my code isn't the best or most optimized, but it should nevertheless work, as I have tried it already with another blocking command under Windows and it worked.
Thanks in advance for every help I get.
I've solved the problem by simply not running the command directly, because that throws buffer problems, so I now don't run the command rfcomm connect hci0 xx:xx:xx:xx:xx:xx, instead I run stdbuf -o0 rfcomm connect hci0 xx:xx:xx:xx:xx:xx, to avoid buffering problems.

Killing a C# process gracefully not working

I have an application that spawns multiples threads, one of which runs an iPerf executable which is used to monitor network reliability. This process will run indefinitely, until the user attempts to close the window. This is where the issue comes in. I am trying to shut that process down gracefully so that the iPerf server does not get hung up, but I can not seem to get this working. I can shut it down just fine if I run the command manually from a command prompt and press Ctrl+c, but this does not seem to be easily done programmatically.
I have tried multiple things, including process.Kill(); or process.StandardInput.Close() or even process.StandardInput.WriteLine("\x3"); but none of these seem to send a graceful shutdown message to the process. process.Kill(); causes the server to hang or fail to start up the next time, and the other two options do not stop the server at all. But the manual ctrl+c works just fine.
Here is a snippet of my code:
iperf_proc = new Process();
iperf_proc.StartInfo.FileName = Application.StartupPath + ".\\iperf3.exe";
String argumentStr = " -c " + test_data.host + " -t 0";
iperf_proc.StartInfo.Arguments = argumentStr;
iperf_proc.StartInfo.UseShellExecute = false;
iperf_proc.StartInfo.RedirectStandardOutput = true;
iperf_proc.StartInfo.RedirectStandardInput = true;
iperf_proc.StartInfo.RedirectStandardError = true;
iperf_proc.Start();
iperfRunning = true;
iperf_proc.BeginOutputReadLine();
iperf_proc.BeginErrorReadLine();
while (false == iperf_proc.HasExited)
{
if (true == processCancelled)
{
iperf_proc.StandardInput.Close(); // Doesn't Work!
iperf_proc.StandardInput.WriteLine("\x3"); // Doesn't Work!
iperf_proc.StandardInput.Flush(); // Doesn't Work!
}
}
iperf_proc.WaitForExit();
Any help is greatly appreciated. Thank you!
UPDATE:
Based on the suggestion from Hans in the comment, I tried adding some stuff to the code to get the ctrl+c event sent over.
[DllImport("kernel32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool GenerateConsoleCtrlEvent(uint dwCtrlEvent, uint dwProcessGroupId);
private enum CtrlEvents
{
CTRL_C_EVENT = 0,
CTRL_BREAK_EVENT = 1
}
private void closeBtn_Click(object sender, EventArgs e)
{
processCancelled = true;
//iperf_proc.CloseMainWindow();
bool succeeded = GenerateConsoleCtrlEvent((uint)CtrlEvents.CTRL_C_EVENT, (uint)iperf_proc.Id);
}
This did not work at all. The process is still running and it does the function added returns false. I did check that the process id being passed matches the id of the process in task manager. That all is fine, but the GenerateConsoleCtrlEvent function returns false. Any idea why this may be?
BeginOutputReadLine
Link describes how to do exactly what you are looking for in the example.
Why not use the built in Exited event to wait on so you are not blocking? Especially if you are spawning multiple threads. If you want to block then WaitForExit() is available as well.
if (true == processCancelled)
{
iperf_proc.StandardInput.Close(); // Doesn't Work!
iperf_proc.StandardInput.WriteLine("\x3"); // Doesn't Work!
iperf_proc.StandardInput.Flush(); // Doesn't Work!
}
If you close the standard input, how are you going to write/flush it?
After you have WaitForExit() you also need to Close()

Monitoring process to be always running

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.

Launch JavaScript from Website / Exit Application

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();

Process.Start is blocking

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));
}
}

Categories

Resources