Use ProcessExecution to start 2 applications in order [duplicate] - c#

This question already has answers here:
How to make GUI wait for windows service?
(5 answers)
Closed 3 years ago.
I want to start 2 related applications. First, I want to start my "Service" application and then my "Client" application. It does not consistently work. Sometimes the client starts up too fast and ends up not being connected to the service. Can someone show me where I need to change my code to work correctly and have the client only start after the service has completely started?
public class Program
{
public static void Main(string[] args)
{
Console.WriteLine("Starting Service");
StartService();
if (IsServiceRunning())
{
Console.WriteLine("Starting Client");
StartClient();
}
Console.ReadLine();
}
private static void StartClient()
{
ProcessStartInfo startInfo = new ProcessStartInfo()
{
WorkingDirectory = #"C:\Client",
FileName = "Client.exe"
};
Process.Start(startInfo);
}
private static bool IsServiceRunning()
{
Console.WriteLine("Check to see is running...");
Process[] pname = Process.GetProcessesByName("MyCommonService");
int runningCheck = 0;
if (pname.Length == 0 || runningCheck < 10)
{
Console.WriteLine("Did not find the process. Check again...");
runningCheck += 1;
Thread.Sleep(250);
IsServiceRunning();
}
Thread.Sleep(1000);
return true;
}
private static void StartService()
{
Console.WriteLine("Starting Service");
ProcessStartInfo startInfo = new ProcessStartInfo()
{
WorkingDirectory = #"C:\Service",
FileName = "MyCommonService.exe"
};
Process.Start(startInfo);
}
}

Looks like that'll always depend on how long it takes for the service to "completely start". If the service needs to do network operations to "completely start", you might have no guarantee of when the service has "completely started". Instead of simply waiting what it looks like 3,500 milliseconds, you can use interprocess communication.
What is the simplest method of inter-process communication between 2 C# processes?
Basic idea is to get your service process to communicate back to your program, and if it gives back a string that shows the service has started, only then start your client process.

Related

running multiple threads with continous value returns (ping program)

good day
I have taken up a project that as a bases needs insernt a command into cmd "ping x.x.x.x -t" and the program needs to return the output until a specified parameter
I am considering threads as my unterstanding in multithreading is limited, I am unable to continue without guidance
my ping class which recieves a string ip, adds it to a precompiled command string, etc.
I am aware of the built in ping class for this use, but I would prefer the "longer" method since i would gain valueble information/experience from this
main object class: ping
class ping
{
Process proc;
ProcessStartInfo psi;
string ip_address;
bool bStop = false;
public ping(string ip)
{
ip_address = ip;
}
public void StartPing()
{
string cmdInput;
psi = new ProcessStartInfo(Environment.GetEnvironmentVariable("COMSPEC"));
psi.RedirectStandardInput = true;
psi.RedirectStandardOutput = true;
psi.UseShellExecute = false;
proc = Process.Start(psi);
proc.StandardInput.WriteLine("ping " + ip_address + " -t");
cmdInput = proc.StandardOutput.ReadLine();
cmdInput = proc.StandardOutput.ReadLine();
cmdInput = proc.StandardOutput.ReadLine();
cmdInput = proc.StandardOutput.ReadLine();
cmdInput = proc.StandardOutput.ReadLine();
cmdInput = proc.StandardOutput.ReadLine();
while (bStop == false)
{
cmdInput = proc.StandardOutput.ReadLine();
Console.WriteLine(returnPing(cmdInput));
}
proc.Close();
}
private string returnPing(string cmdInput)
{
int start, end;
string ping;
if (cmdInput.IndexOf("Reply") != -1 && cmdInput.IndexOf("time") != -1)
{
start = cmdInput.IndexOf("time=") + 5;
end = cmdInput.IndexOf("ms");
ping = cmdInput.Substring(start, end - start);
return ping;
}
else return "-1";
}
and thread_handler class, which manages mutliple instances of the ping method, please not the console.writeline is a temporary output which I will change in the future
class thread_handler
{
string[] ipList;
private IList<Thread> threadList;
public thread_handler(string[] ip)
{
ipList = ip;
threadList = new List<Thread>();
createThreads();
}
private void createThreads()
{
foreach (string item in ipList)
{
ping NewPing = new ping(item);
Thread newPingThread = new Thread(NewPing.StartPing);
newPingThread.IsBackground = true;
newPingThread.Name = string.Format("{0}", item);
threadList.Add(newPingThread);
}
startAllThreads();
}
private void startAllThreads()
{
foreach (Thread item in threadList)
{
item.Start();
}
}
}
Program
class Program
{
static string[] ipList;
static void Main(string[] args)
{
ipList = new String[3];
readData();
sendData();
}
private static void sendData()
{
thread_handler thIp = new thread_handler(ipList);
}
private static void readData()
{
//use sll with name defintions and ip address's with metadata
ipList[0] = "10.0.0.2";
ipList[1] = "telkom_exchange";
ipList[2] = "goo.gl";
}
The aim of this program is (with gui changes in future) for a simple console with respective dimensions to constantly ping certain ip address's (we have ban infrastructure, thus program is for informative purposes), constantly updating on every ping reply
I do not want anyone to finish this program, I simply require assistance with running multiple instances (or maybe "threads") of this pinging, thus
each thread as it runs the "StartPing()" method, it should return an output, e.g. simply output the ping into the console, but it doesnt...
Output:
The process tried to write to a nonexistent pipe.
The process tried to write to a nonexistent pipe.
then hangs
The way you read from the child process is not right. This is a surprisingly complicated task. I don't know why you are getting this specific error message but it sounds like it has to do with process standard output redirection. For example you have not redirected standard error.
I suggest you use one of the top voted snippets of stack overflow, to be found by: site:stackoverflow.com process RedirectStandardOutput. There are hundreds of such questions. Most solutions are subtly wrong.
This is a good checklist.
You should use the ping class to execute a ping. This class allows you to control many details.
The call to ping.exe with Process.Start() involves way too much overhead and complicates things (as you experienced in your try)
As simple as it is, redirecting standard input and output did it, with a tweak or two, voila

C# Get standard input/output/error of running, NOT child process

My question is pretty simple: how do I get the standard output/input/error of a process I did not start? Let's say I have some program (that is not mine) XYZ that runs all day and prints things to stdout. I want to be able to start my C# application and start reading XYZ's output. Then close my C# application and restart it 2 hours later and continue reading the output (not necessarily where I left off but that would be a plus).
I know this can be achieved if XYZ is a child process of mine with
serverProcess = Process.Start(new ProcessStartInfo()
{
RedirectStandardError = true,
RedirectStandardInput = true,
RedirectStandardOutput = true,
WorkingDirectory = WorkingDir,
Arguments = Args,
FileName = "XYZ",
UseShellExecute = false
});
serverProcess.OutputDataReceived += serverProcess_OutputDataReceived;
serverProcess.ErrorDataReceived += serverProcess_OutputDataReceived;
serverProcess.BeginOutputReadLine();
serverProcess.BeginErrorReadLine();
But this is not the case since XYZ is is completely independent of my application, and needs to keep running regardless of what I do to it.
It is worth noting that (if it helps) I can start XYZ myself (with those redirection parameters). It's just that my lifecycle needs to be completely independent of XYZ, and I need to be able to "reattach" after I relaunch.
I have seen some suggestions using Get/SetStdHandle but most of them claimed to not work, and I din't quite understand how to apply them anyways.
Thanks for any advice!
It is worth noting that (if it helps) I can start XYZ myself (with those redirection parameters). It's just that my lifecycle needs to be completely independent of XYZ, and I need to be able to "reattach" after I relaunch.
Here is a simple implementation of what I suggested in the comments (publishing data through an intermediary process).
basicaly the sample is composed of 3 main parts
1. Sample XYZ Process
which in our case, is a simple console application that spits a Hello from XYZ message every second.
class Program
{
static void Main(string[] args)
{
var count = 0;
while (true)
{
Console.WriteLine("Hello from XYZ "+count);
count++;
Thread.Sleep(1000);
}
}
}
2. Intermediary Process
which should start XYZ and redirect its output to itself and then publish it through. for publishing part we use ZeroMQ library here that can be obtained easily from nuget.
class Program
{
private static Socket _pub;
static void Main(string[] args)
{
using (var context = new Context())
{
_pub = context.Socket(SocketType.PUB);
_pub.Bind("tcp://*:2550");
StartXyz();
Console.WriteLine("Press any key to close middle process...");
Console.ReadKey();
}
}
private static void StartXyz()
{
var serverProcess = Process.Start(new ProcessStartInfo
{
RedirectStandardError = true,
RedirectStandardInput = true,
RedirectStandardOutput = true,
WorkingDirectory = AppDomain.CurrentDomain.BaseDirectory,
Arguments = string.Empty,
FileName = "XYZ.exe",
UseShellExecute = false
});
serverProcess.OutputDataReceived += serverProcess_OutputDataReceived;
serverProcess.ErrorDataReceived += serverProcess_OutputDataReceived;
serverProcess.BeginOutputReadLine();
serverProcess.BeginErrorReadLine();
}
private static void serverProcess_OutputDataReceived(object sender, DataReceivedEventArgs e)
{
_pub.Send(e.Data, Encoding.UTF8);
Console.WriteLine(e.Data + " pushed.");
}
}
3. Consumer Process
and finally we have our process, which consumes redirected data from XYZ.
class Program
{
static void Main(string[] args)
{
using (var context = new Context())
{
var sub = context.Socket(SocketType.SUB);
sub.Connect("tcp://localhost:2550");
sub.Subscribe(string.Empty, Encoding.UTF8);
while (true)
{
var data = sub.Recv(Encoding.UTF8);
Console.WriteLine(data);
}
}
}
}

Redirecting standard output

I have a C# application A which calls another C# application B, which calls multiple instances of application C.
I would like to redirect the output of application C to the output of application A.
I already have a working redirection of the output of application B into the output of application A.
Now, from within application B's code, I'm redirecting every process's output, and I'm printing the redirected output to the console. Unfortunately, for some reason, nothing is printed.
(I'm currently testing it without using application A - I'm only running application B).
Here is the code:
private void runSingleFile (string execFile, string commandArgs)
{
Process processToRun = new Process();
processToRun .StartInfo.FileName = execFile;
processToRun .StartInfo.Arguments = commandArgs;
processToRun .StartInfo.UseShellExecute = false;
processToRun .StartInfo.RedirectStandardOutput = true;
processToRun .OutputDataReceived += outputRedirection;
processToRun.Start();
Console.WriteLine("");
Thread.Sleep(100);
processToRun.BeginOutputReadLine();
}
private void outputRedirection(object sendingProcess, DataReceivedEventArgs outLine)
{
try
{
if (outLine.Data != null)
Console.WriteLine(outLine.Data);
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
return;
}
}
Any ideas?
The .net Process object doesn't make it easy for one to "do the right thing" with respect to correctly handling the IO.
These pages list some of the concerns that need to be dealt with:
MSDN's ProcessStartInfo.RedirectStandardOutput Property page
Raymond's blog Be careful when redirecting both a process's stdin and stdout to pipes...
C# test.net's How to use System.Diagnostics.Process correctly
From your code sample, here are some of the items that you will want to look at:
You will want to capture both stderr and stdin (the latter should be immediately closed if not used).
You also need to be aware that you can still receive events on your outputRedirection callback after the child process has exited.
The code you have posted works. Given test program
// ConsoleApplication2.exe
static void Main(string[] args)
{
Console.WriteLine("Test1...");
Console.WriteLine("Test2...");
System.Threading.Thread.Sleep(100);
Console.WriteLine("Test3...");
}
called as :
static void Main(string[] args)
{
runSingleFile("ConsoleApplication2.exe", "");
runSingleFile("ConsoleApplication2.exe", "");
runSingleFile("ConsoleApplication2.exe", "");
Console.ReadLine();
}
produces output :
Clearly something else is not working in another part of your code (Something you have not shown us).
The most likely explanation, if application C is working correctly, is that application B is terminating before all instances of C have completed. You may have to add some code that makes B wait for all instances of C to return.
Note that :
static void Main(string[] args)
{
runSingleFile("ConsoleApplication2.exe", "");
runSingleFile("ConsoleApplication2.exe", "");
runSingleFile("ConsoleApplication2.exe", "");
//Console.ReadLine(); // ** Don't wait!
}
completes immediately and fails to return some or all of the data (especially if you remove the Sleep call in runSingleFile.
Consider :
static long processCount = 0; //ADD
static void runSingleFile(string execFile, string commandArgs)
{
Interlocked.Increment(ref processCount); //ADD
Process processToRun = new Process();
processToRun.StartInfo.FileName = execFile;
processToRun.StartInfo.Arguments = commandArgs;
processToRun.StartInfo.UseShellExecute = false;
processToRun.StartInfo.RedirectStandardOutput = true;
processToRun.OutputDataReceived += outputRedirection;
processToRun.EnableRaisingEvents = true; //ADD
processToRun.Exited += processExited; //ADD
processToRun.Start();
Console.WriteLine("");
processToRun.BeginOutputReadLine();
}
static void processExited(object sender, EventArgs e)
{
Interlocked.Decrement(ref processCount);
}
with
static void Main(string[] args)
{
runSingleFile("ConsoleApplication2.exe", "");
runSingleFile("ConsoleApplication2.exe", "");
runSingleFile("ConsoleApplication2.exe", "");
while (Interlocked.Read(ref processCount) > 0)
{
System.Threading.Thread.Sleep(100);
}
}
The above then makes application B wait until all spawned processes have returned. The example is simplistic and obviously can be improved upon, but it demonstrates the problem, I think, and offers a method for the solution.
You might be tempted to use something more elegant like WaitHandle.WaitAll(), but this does introduce the problem that josh noted where your output events may not fire until after the process terminates - the process handle will signal that it has terminated but its posted messages may still be in the queue. Waiting on the Exited event tidies up that race condition since that event will always be the last message in the queue (AFAIK).
Also, note the use of Interlocked functions here - Console.WriteLine is threadsafe but other variable access is not. Since there is no synchronization context in a console application the events raised by spawned processes are handled by threads in the threadpool (not the main thread of the console application). This introduces all of the issues associated with multithreading which must be managed appropriately.

Sending message from one C# console application to another

First of all, I've read all related topics and they gave general idea but implementation doesn't work for me:
Send strings from one console application to another
How to send input to the console as if the user is typing?
Sending input/getting output from a console application (C#/WinForms)
I have a console application that is doing some actions in background until cancellation is requested. Typical usage scenario is :
1) Execute application
2) Enter input data
3) Issue start command
4) After some time passes, enter stop command
5) Exit application
Child application Program.cs :
static void Main()
{
Console.WriteLine("Enter input parameter : ");
var inputParameter = Console.ReadLine();
Console.WriteLine("Entered : " + inputParameter);
var tokenSource = new CancellationTokenSource();
var token = tokenSource.Token;
Task.Factory.StartNew(() =>
{
while (true)
{
if (token.IsCancellationRequested)
{
Console.WriteLine("Stopping actions");
return;
}
// Simulating some actions
Console.Write("*");
}
}, token);
if (Console.ReadKey().KeyChar == 'c')
{
tokenSource.Cancel();
Console.WriteLine("Stop command");
}
Console.WriteLine("Finished");
Console.ReadLine();
}
What I'm looking for is some sort of host utility to control this application - spawn multiple instances and perform required user actions on each instance.
Host application Program.cs :
static void Main()
{
const string exe = "Child.exe";
var exePath = System.IO.Path.GetFullPath(exe);
var startInfo = new ProcessStartInfo(exePath)
{
RedirectStandardOutput = true,
RedirectStandardInput = true,
WindowStyle = ProcessWindowStyle.Hidden,
WindowStyle = ProcessWindowStyle.Maximized,
CreateNoWindow = true,
UseShellExecute = false
};
var childProcess = new Process { StartInfo = startInfo };
childProcess.OutputDataReceived += readProcess_OutputDataReceived;
childProcess.Start();
childProcess.BeginOutputReadLine();
Console.WriteLine("Waiting 5s for child process to start...");
Thread.Sleep(5000);
Console.WriteLine("Enter input");
var msg = Console.ReadLine();
// Sending input parameter
childProcess.StandardInput.WriteLine(msg);
// Sending start command aka any key
childProcess.StandardInput.Write("s");
// Wait 5s while child application is working
Thread.Sleep(5000);
// Issue stop command
childProcess.StandardInput.Write("c");
// Wait for child application to stop
Thread.Sleep(20000);
childProcess.WaitForExit();
Console.WriteLine("Batch finished");
Console.ReadLine();
}
When I run this tool, after first input it crashes with "has stopped working" error and prompt to send memory dump to Microsoft. Output window in VS shows no exceptions.
Guess this problem occurs somewhere between applications and may be because of output stream buffer overflow (child app is writing a lot of stars each second which mimics real output which may be huge) and I yet have no idea how to fix it. I don't really need to pass child's output to host (only send start-stop commands to child), but commenting RedirectStandardOutput and OutputDataReceived doesn't fix this problem. Any ideas how to make this work?
I would recommend using NamedPipeServerStream and NamedPipeClientStream, which allows you to open a stream which will communicate between processes on a given machine.
First, this will create a pipe server stream and wait for someone to connect to it:
var stream = new NamedPipeServerStream(this.PipeName, PipeDirection.InOut);
stream.WaitForConnection();
return stream;
Then, this will connect to that stream (from your other process), allowing you to read / write in either direction:
var stream = new NamedPipeClientStream(".", this.PipeName, PipeDirection.InOut);
stream.Connect(100);
return stream;
Another alternative is to use MSMQ, you can find a good tutorial here
I would advise to look to the Working with memory mapped files in .NET 4
http://blogs.msdn.com/b/salvapatuel/archive/2009/06/08/working-with-memory-mapped-files-in-net-4.aspx
It's fast and efficient.

Killing Java Process from C# Console App

I posted about this a little while ago, but I resolved the other issue and ran into one more. I am about to deploy this program to 28 hosting machines so I want to make sure this is working before I do so.
I wrote a little c# NET application that is basically a wrapper for a Java application, when my app starts, the Java app starts, when my app closes, it closes, and so on.
Everything works properly except that when I close my application, the Java application continues to run. When I create the process, I store the Process var in a variable outside of the methods, and then use that when my application goes to shutdown. For whatever reason though it is not terminating the Java application.
class Program
{
private static Process minecraftProcess;
public static void LaunchMinecraft(String file, String memoryValue)
{
String memParams = "-Xmx" + memoryValue + "M" + " -Xms" + memoryValue + "M ";
String args = memParams + "-jar " + file + " nogui";
ProcessStartInfo processInfo = new ProcessStartInfo("java.exe", args);
processInfo.CreateNoWindow = true;
processInfo.UseShellExecute = false;
try
{
//using (Process minecraftProcess = Process.Start(processInfo))
using (minecraftProcess = Process.Start(processInfo))
{
minecraftProcess.WaitForExit();
}
}
catch
{
// Log Error
}
}
static void Main(string[] args)
{
Arguments CommandLine = new Arguments(args);
// Hook ProcessExit Event
AppDomain.CurrentDomain.ProcessExit += new EventHandler(Current_ProcessExit);
if (CommandLine["file"] != null && CommandLine["memory"] != null)
{
// Launch the Application (Command Line Parameters)
LaunchMinecraft(CommandLine["file"], CommandLine["memory"]);
}
else
{
// Launch the Application (Default Parameters)
LaunchMinecraft("minecraft_server.jar", "1024");
}
}
static void Current_ProcessExit(object sender, EventArgs e)
{
System.Threading.Thread.Sleep(10000);
// If we have an active Minecraft Service, Shut it down
if (minecraftProcess != null)
{
minecraftProcess.Kill();
}
}
}
You can't Sleep in a ProcessExit handler.
The documentation states:
The total execution time of all
ProcessExit event handlers is limited,
just as the total execution time of
all finalizers is limited at process
shutdown. The default is two seconds.
An unmanaged host can change this
execution time by calling the
ICLRPolicyManager::SetTimeout method
with the OPR_ProcessExit enumeration
value.
Nevermind, I just realized the minecraftProcess variable is static.
Don't know if you did not solve this issue by yourself but:
You should be aware that there are Start methods for instances (returning bool) and static (returning a object).
You should not use using with something other than using-local variables!
Just this should work fine:
minecraftProcess = Process.Start(processInfo)
minecraftProcess.WaitForExit();

Categories