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:\\");
}
}
Related
Is it somehow possible that if I start my program like 10 times fast in a row, but only one at a time should do something. The other keep waiting that the working program is finished or stopped.
So in the end, if I open my program 10 times, all 10 programs should be working in a row, not simultaneously.
Is this possible in c#?
You can use a named EventWaitHandle to do this, for example:
using System;
using System.Threading;
namespace Demo
{
static class Program
{
static void Main()
{
using (var waitHandle = new EventWaitHandle(true, EventResetMode.AutoReset, "MyHandleName"))
{
Console.WriteLine("Waiting for handle");
waitHandle.WaitOne();
try
{
// Body of program goes here.
Console.WriteLine("Waited for handle; press RETURN to exit program.");
Console.ReadLine();
}
finally
{
waitHandle.Set();
}
Console.WriteLine("Exiting program");
}
}
}
}
Try running a few instances of this console app and watch the output.
You can use system wide Mutex or system wide Semaphore. If you create Mutex or Semaphore with name it become visible for whole system - in other words it can be visible from other processes.
Mutex syncMutex = new Mutex(false, "NAME OF MUTEX");
try
{
if(!syncMutex.WaitOne(MUTEX_TIMEOUT))
{
//fail to get mutex
return;
}
//mutex obtained do something....
}
catch(Exception ex)
{
//handle error
}
finally
{
//release mutex
syncMutex.ReleaseMutex();
}
I have an assignment in C# involving automation. My code is mainly based off things I have found online. My current problem is I am trying to read in IP addresses line by line from a CSV file into an array, pinging each object of the array, and appending the object so that each object will read "IP, status(if the ping was successful), response time"
I am trying to use a foreach loop but am running into errors. I am on a Mac so it is using mono. Any help would be appreciated.
(Full assignment below if it helps explain anything)
Starting with a premade C# console application, your application will upon running allow for three commands – start, stop, and exit. The application will, upon first running, ask the user for a CSV file (the user must provide a CSV file). This file will contain web addresses (1 per line) – the professor will supply the initial file.
Your application will be setup with a timer so that every time the timer runs, it pings the provided web addresses, gathering whether the server responds or not and the response time of each server. The timer should run continuously from the point the user types “start” until they type “stop” or “exit”. The data will be recorded back to another CSV file, containing the web address, response time, and whether or not the server responded at all.
using System;
using System.Timers;
using System.IO;
using System.Linq;
using System.Net.NetworkInformation;
using System.Collections.Generic;
using Microsoft.VisualBasic;
namespace MT_proj4
{
public class Program
{
public static String[] addressArray = File.ReadAllLines("Project04_URLs.csv");
public static string IP;
public bool status;
public string time;
public static void Main()
{
foreach (string s in addressArray)
{
IP = Console.ReadLine();
bool PingHost(string)
{
bool pingable = false;
#pragma warning disable XS0001 // Find APIs marked as TODO in Mono
Ping pinger = new Ping();
#pragma warning restore XS0001 // Find APIs marked as TODO in Mono
try
{
PingReply reply = pinger.Send(IP);
pingable = reply.Status == IPStatus.Success;
}
catch (PingException)
{
return false;
}
for (int i = 0; i < addressArray.Length; i++)
{
addressArray[i] = addressArray[i] + pingable;
}
}
}
}
static void TimerClass()
{
Timer timer = new Timer(5000);
timer.Elapsed += HandleTimer;
timer.Start();
Console.WriteLine("Type 'exit' to close...");
Console.WriteLine("Enter a command...");
while (true)
{
Console.Write("Command: ");
string command = Console.ReadLine();
Console.WriteLine("Command entered: " + command);
if (command.ToLower() == "stop")
timer.Stop();
else if (command.ToLower() == "exit")
break;
}
}
static void HandleTimer(Object source, ElapsedEventArgs e)
{
Console.WriteLine("\nHandler not implemented...");
}
}
I would restructure your solution a bit. The ping code should run its own thread. Remove the timer, and simply block on Console.ReadLine(). If the results are not expected, repeat until you get either stop or exit.
The reason is the ping work and the console processing are on the same thread. These will block.
Try this:
class Program
{
static void Main(string[] args)
{
Console.WriteLine("pinging....until stop command");
Thread pinger = new Thread(DoPinging);
pinger.Start();
while (true)
{
string command = Console.ReadLine();
if (command.ToLower() == "stop")
break;
else if (command.ToLower() == "exit")
break;
Console.WriteLine("Ignoring-> " + command);
}
pinger.Abort();
}
static void DoPinging()
{
// here goes the pinging code
}
}
In your example code, it looks like you want to read input for ping from Console as well, after the line read, if the value doesn't equal the stop commands (stop, exit), put the value into a queue and let the ping code read from the queue.
You mention reading a CSV file for the addresses to ping (but your example code doesn't reference a file). You can take this as a command line argument (string[] passed in main) and do the work for processing the file in the DoPinging method.
If you want me to add more detail to that, please comment below and I will work on that.
Thnx
Matt
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.
I have a situation where I need to have only one instance of a program running at the same time.
This would be trivial like this:
class OneAtATimePlease
{
static void Main()
{
// Naming a Mutex makes it available computer-wide. Use a name that's
// unique to your company and application (e.g., include your URL).
using (var mutex = new Mutex (false, "oreilly.com OneAtATimeDemo"))
{
// Wait a few seconds if contended, in case another instance
// of the program is still in the process of shutting down.
if (!mutex.WaitOne (TimeSpan.FromSeconds (3), false))
{
Console.WriteLine ("Another app instance is running. Bye!");
return;
}
RunProgram();
}
}
static void RunProgram()
{
Console.WriteLine ("Running. Press Enter to exit");
Console.ReadLine();
}
}
Except for the small detail, that I need the EXISTING process to terminate, not the new one.
I tried making a semaphore the existing process could listen to after grabbing the above mutex, but because I want it to wait for the semaphore then I can end up in a situation where the semaphore is always signaled and thus it doesn't work.
Anyone have a good idea on how to solve this problem?
You need inter-process communication, to send a signal to the existing application. For C#, see IPC Mechanisms in C# - Usage and Best Practices.
Cine, I've written a two-Mutex logic. The first one is the "execution lock", while the second is the "monitor lock".
When the first process can't acquire the monitor lock, it will exit and release the execution lock for the new process.
I'm not sure if this is the best solution, and any feedback will be welcome.
C#:
class Program
{
private static string processName = DateTime.Now.ToString("hh.mm.ss");
private static bool exitProcess;
private static Mutex firstLock
{
get
{
return new Mutex(false, "stackoverflow.com/questions/11304052/");
}
}
private static Mutex secondLock
{
get
{
return new Mutex(false, "stackoverflow.com/questions/11304052/ #2");
}
}
static void Main(string[] args)
{
Console.WriteLine(string.Format("Process {0} starting", processName));
exitProcess = false;
while (true)
{
using (firstLock)
{
Console.WriteLine(string.Format("Process {0} trying to get #1 mutex", processName));
if (!firstLock.WaitOne(TimeSpan.FromSeconds(1), false))
{
Console.WriteLine(string.Format("Process {0} #1 mutex in use, waiting for release", processName));
bool killFirstApp = false;
while (!killFirstApp)
{
killFirstApp = LockSecondMutex();
}
continue;
}
new Thread(MonitorSecondMutex).Start();
RunProgram();
firstLock.ReleaseMutex();
break;
}
}
}
static void RunProgram()
{
while (!exitProcess)
{
Console.WriteLine(string.Format("Process {0} running", processName));
Thread.Sleep(1000);
}
}
static void MonitorSecondMutex()
{
while (true)
{
using (secondLock)
{
if (!secondLock.WaitOne(TimeSpan.FromSeconds(2), false))
{
Console.WriteLine(string.Format("Process {0} lost second mutex. Will now exit.", processName));
exitProcess = true;
break;
}
secondLock.ReleaseMutex();
}
Thread.Sleep(500);
}
}
static bool LockSecondMutex()
{
while (true)
{
using (secondLock)
{
if (!secondLock.WaitOne(TimeSpan.FromSeconds(2), false))
{
continue;
}
Thread.Sleep(5000);
secondLock.ReleaseMutex();
}
return true;
}
}
}
You could possibly get this done by requesting access to some limited system-wide resource, such as port. Your application could bind a socket to a specific port on launch. If it fails to bind, send a termination signal to the running instance and try again.
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));
}
}