I currently have mutex in my app that allows only 1 instance to run. My question is, how do I take this code now, and transform it to close the currently running instance and allow a new one to open?
The problem I am trying to solve: My app takes in args and needs to be reopened often with new params. Currently, without mutex it can open an infinite number of times. I would like only 1 instance with the newest set of params to run.
Thanks,
Kevin
Some Code
bool createdMutex = true;
Mutex mutex = new Mutex(true, "VideoViewerApp", out createdMutex);
if (createdMutex && mutex.WaitOne())
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new frmVideo(args[0], args[1], args[2], args[4], args[5]));
mutex.ReleaseMutex();
}
mutex.close();
The mutex was not meant for interprocess event notification, so there is no way to close another process by using mutexes. What I would recommend would be to do something like what is recommended in this question.
I'll combine the two answers there into something like what I've used:
Process[] processes = Process.GetProcesses();
string thisProcess = Process.GetCurrentProcess().MainModule.FileName;
string thisProcessName = Process.GetCurrentProcess().ProcessName;
foreach (var process in processes)
{
// Compare process name, this will weed out most processes
if (thisProcessName.CompareTo(process.ProcessName) != 0) continue;
// Check the file name of the processes main module
if (thisProcess.CompareTo(process.MainModule.FileName) != 0) continue;
if (Process.GetCurrentProcess().Id == process.Id)
{
// We don't want to commit suicide
continue;
}
// Tell the other instance to die
process.CloseMainWindow();
}
Related
I have deployed a ClickOnce Windows Forms application (App A)
Another application (App B) starts App A with a filename as parameter.
I do this with this Code
var basePath = Environment.GetFolderPath(Environment.SpecialFolder.Programs);
var location = String.Format(#"{0}\{1}\{2}\{3}",
basePath, "MyCompany", "MyProduct", "MyApp.appref-ms");
var fileName = #"c:\temp\somefile.ext";
var uri = new Uri(fileName).ToString();
Process.Start(location, uri);
App A grabs the file name from AppDomain.CurrentDomain.SetupInformation.ActivationArguments.ActivationData[0] and show the content.
This works like a charm. However, now I want App B to wait for App A to exit.
But a call to Process.WaitForExit() returns instantly.
Is there a way to open a ClickOnce App and wait for it to exit? I can, if necessary, change the way the app is opend but the requirement is that I need to run the app as a ClickOnce app (I know that somewhere in my user profile AppData\Local\Apps\2.0\ folder the exe exists and can be started directly but If I do that ApplicationDeployment.IsNetworkDeployed is false and ApplicationDeployment.CurrentDeployment is null. In that I loose the ClickOnce Update Capabilities).
my suggestion would be to use Mutex in App A, and let App B check and wait for it. This is the cleanest way from my point of view.
App A does this when starts:
private static Mutex mutex;
public static void Main()
{
// if you want your app to be limited to a single instance
// across ALL SESSIONS (multiple users & terminal services), then use the following line instead:
// string mutexName = string.Format("Global\\{0}", ProgramInfo.AssemblyGuid);
var mutexName = string.Format("Local\\{0}", SOME_SHARED_GUID);
mutex = new Mutex(true, mutexName, out singleInstance);
if (singleInstance == false)
{
// that means your app has more than one instance running
// you need to decide what to do here.
}
// rest of initialization code
Application.Run();
// release the mutex so App B can continue
mutex.ReleaseMutex();
}
and App B just waits for the mutex to be released:
Process.Start(location, uri);
Thread.Sleep(5000); // give it 5 seconds or so to check for updates and start
var mutexName = string.Format("Local\\{0}", SOME_SHARED_GUID);
mutex = new Mutex(false, mutexName);
mutex.WaitOne();
The problem is that starting the appref-ms process does not actually start the application it starts the deployment manifest, which then launches the application itself, so the process you are starting exits straight away.
You can add a check to see when you application has started if you know the name (which I assume you do) like this:
string myAppName = "YourAppName";
DateTime startTime = DateTime.Now;
int newProcessId = 0;
List<int> runningProcessIds = new List<int>();
//find all the running processes and record their Ids
foreach (void proc_loopVariable in Process.GetProcessesByName(myAppName)) {
proc = proc_loopVariable;
runningProcessIds.Add(proc.Id);
}
//start the new process
Process.Start(location);
//wait for the new application to be started
while (!(Process.GetProcessesByName(myAppName).Count != runningProcessIds.Count)) {
//timeout if we have not seen the application start
if ((DateTime.Now - startTime).TotalSeconds > 30)
break;
}
//loop through all the running processes again to find the id of the one that has just started
foreach (void proc_loopVariable in Process.GetProcessesByName(myAppName)) {
proc = proc_loopVariable;
if (!runningProcessIds.Contains(proc.Id)) {
newProcessId = proc.Id;
break;
}
}
//wait for the application to finish
Process.GetProcessById(newProcessId).WaitForExit();
Debug.WriteLine("Finished");
I want to build my application with the function to restart itself. I found on codeproject
ProcessStartInfo Info=new ProcessStartInfo();
Info.Arguments="/C choice /C Y /N /D Y /T 3 & Del "+
Application.ExecutablePath;
Info.WindowStyle=ProcessWindowStyle.Hidden;
Info.CreateNoWindow=true;
Info.FileName="cmd.exe";
Process.Start(Info);
Application.Exit();
This does not work at all...
And the other problem is, how to start it again like this?
Maybe there are also arguments to start applications.
Edit:
http://www.codeproject.com/script/Articles/ArticleVersion.aspx?aid=31454&av=58703
I use similar code to the code you tried when restarting apps. I send a timed cmd command to restart the app for me like this:
ProcessStartInfo Info = new ProcessStartInfo();
Info.Arguments = "/C ping 127.0.0.1 -n 2 && \"" + Application.ExecutablePath + "\"";
Info.WindowStyle = ProcessWindowStyle.Hidden;
Info.CreateNoWindow = true;
Info.FileName = "cmd.exe";
Process.Start(Info);
Application.Exit();
The command is sent to the OS, the ping pauses the script for 2-3 seconds, by which time the application has exited from Application.Exit(), then the next command after the ping starts it again.
Note: The \" puts quotes around the path, incase it has spaces, which cmd can't process without quotes.
Hope this helps!
Why not use
Application.Restart();
??
More on Restart
Why not just the following?
Process.Start(Application.ExecutablePath);
Application.Exit();
If you want to be sure the app does not run twice either use Environment.Exit(-1) which kills the process instantaneously (not really the nice way) or something like starting a second app, which checks for the process of the main app and starts it again as soon as the process is gone.
You have the initial application A, you want to restart.
So, When you want to kill A, a little application B is started, B kill A, then B start A, and kill B.
To start a process:
Process.Start("A.exe");
To kill a process, is something like this
Process[] procs = Process.GetProcessesByName("B");
foreach (Process proc in procs)
proc.Kill();
A lot of people are suggesting to use Application.Restart. In reality, this function rarely performs as expected. I have never had it shut down the application I am calling it from. I have always had to close the application through other methods such as closing the main form.
You have two ways of handling this. You either have an external program that closes the calling process and starts a new one,
or,
you have the start of your new software kill other instances of same application if an argument is passed as restart.
private void Application_Startup(object sender, StartupEventArgs e)
{
try
{
if (e.Args.Length > 0)
{
foreach (string arg in e.Args)
{
if (arg == "-restart")
{
// WaitForConnection.exe
foreach (Process p in Process.GetProcesses())
{
// In case we get Access Denied
try
{
if (p.MainModule.FileName.ToLower().EndsWith("yourapp.exe"))
{
p.Kill();
p.WaitForExit();
break;
}
}
catch
{ }
}
}
}
}
}
catch
{
}
}
Winforms has the Application.Restart() method, which does just that. If you're using WPF, you can simply add a reference to System.Windows.Forms and call it.
Another way of doing this which feels a little cleaner than these solutions is to run a batch file which includes a specific delay to wait for the current application to terminate. This has the added benefit of preventing the two application instances from being open at the same time.
Example windows batch file ("restart.bat"):
sleep 5
start "" "C:\Dev\MyApplication.exe"
In the application, add this code:
// Launch the restart batch file
Process.Start(#"C:\Dev\restart.bat");
// Close the current application (for WPF case)
Application.Current.MainWindow.Close();
// Close the current application (for WinForms case)
Application.Exit();
My solution:
private static bool _exiting;
private static readonly object SynchObj = new object();
public static void ApplicationRestart(params string[] commandLine)
{
lock (SynchObj)
{
if (Assembly.GetEntryAssembly() == null)
{
throw new NotSupportedException("RestartNotSupported");
}
if (_exiting)
{
return;
}
_exiting = true;
if (Environment.OSVersion.Version.Major < 6)
{
return;
}
bool cancelExit = true;
try
{
List<Form> openForms = Application.OpenForms.OfType<Form>().ToList();
for (int i = openForms.Count - 1; i >= 0; i--)
{
Form f = openForms[i];
if (f.InvokeRequired)
{
f.Invoke(new MethodInvoker(() =>
{
f.FormClosing += (sender, args) => cancelExit = args.Cancel;
f.Close();
}));
}
else
{
f.FormClosing += (sender, args) => cancelExit = args.Cancel;
f.Close();
}
if (cancelExit) break;
}
if (cancelExit) return;
Process.Start(new ProcessStartInfo
{
UseShellExecute = true,
WorkingDirectory = Environment.CurrentDirectory,
FileName = Application.ExecutablePath,
Arguments = commandLine.Length > 0 ? string.Join(" ", commandLine) : string.Empty
});
Application.Exit();
}
finally
{
_exiting = false;
}
}
}
This worked for me:
Process.Start(Process.GetCurrentProcess().MainModule.FileName);
Application.Current.Shutdown();
Some of the other answers have neat things like waiting for a ping to give the initial application time to wind down, but if you just need something simple, this is nice.
For .Net application solution looks like this:
System.Web.HttpRuntime.UnloadAppDomain()
I used this to restart my web application after changing AppSettings in myconfig file.
System.Configuration.Configuration configuration = WebConfigurationManager.OpenWebConfiguration("~");
configuration.AppSettings.Settings["SiteMode"].Value = model.SiteMode.ToString();
configuration.Save();
This question already has answers here:
What is the correct way to create a single-instance WPF application?
(39 answers)
Closed 6 years ago.
I have a application but currently it is not a singleton application.
I like to make it singleton application so that its another instance does not exit at the run time .
If this can be done please reply with some sample codes .
I think the following codes will be helpful for you.
Here is the related link:
http://geekswithblogs.net/chrisfalter/archive/2008/06/06/how-to-create-a-windows-form-singleton.aspx
static class Program
{
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
/*====================================================
*
* Add codes here to set the Winform as Singleton
*
* ==================================================*/
bool mutexIsAvailable = false;
Mutex mutex = null;
try
{
mutex = new Mutex(true, "SampleOfSingletonWinForm.Singleton");
mutexIsAvailable = mutex.WaitOne(1, false); // Wait only 1 ms
}
catch (AbandonedMutexException)
{
// don't worry about the abandonment;
// the mutex only guards app instantiation
mutexIsAvailable = true;
}
if (mutexIsAvailable)
{
try
{
Application.Run(new SampleOfSingletonWinForm());
}
finally
{
mutex.ReleaseMutex();
}
}
//Application.Run(new SampleOfSingletonWinForm());
}
}
Here are some good sample applications. Below is one possible way.
public static Process RunningInstance()
{
Process current = Process.GetCurrentProcess();
Process[] processes = Process.GetProcessesByName (current.ProcessName);
//Loop through the running processes in with the same name
foreach (Process process in processes)
{
//Ignore the current process
if (process.Id != current.Id)
{
//Make sure that the process is running from the exe file.
if (Assembly.GetExecutingAssembly().Location.
Replace("/", "\\") == current.MainModule.FileName)
{
//Return the other process instance.
return process;
}
}
}
//No other instance was found, return null.
return null;
}
if (MainForm.RunningInstance() != null)
{
MessageBox.Show("Duplicate Instance");
//TODO:
//Your application logic for duplicate
//instances would go here.
}
Many other possible ways. See the examples for alternatives.
First one.
Second One.
Third One.
The approach I know of is the following. The program must attempt to open a named mutex. If that mutex existed, then exit, otherwise, create the mutex. But this seems to contradict your condition that "its another instance does not exit at the run time". Anyway, maybe this too was helpful
How can I kill some active processes by searching for their .exe filenames in C# .NET or C++?
Quick Answer:
foreach (var process in Process.GetProcessesByName("whatever"))
{
process.Kill();
}
(leave off .exe from process name)
My solution is to use Process.GetProcess() for listing all the processes.
By filtering them to contain the processes I want, I can then run Process.Kill() method to stop them:
var chromeDriverProcesses = Process.GetProcesses().
Where(pr => pr.ProcessName == "chromedriver"); // without '.exe'
foreach (var process in chromeDriverProcesses)
{
process.Kill();
}
Update:
In case if you want to do the same in an asynchronous way (using the C# 8 Async Enumerables), check this out:
const string processName = "chromedriver"; // without '.exe'
await Process.GetProcesses()
.Where(pr => pr.ProcessName == processName)
.ToAsyncEnumerable()
.ForEachAsync(p => p.Kill());
Note: using async methods doesn't always mean code will run faster.
The main benefit is that the foreground thread will be released while operating.
You can use Process.GetProcesses() to get the currently running processes, then Process.Kill() to kill a process.
If you have the process ID (PID) you can kill this process as follow:
Process processToKill = Process.GetProcessById(pid);
processToKill.Kill();
You can Kill a specific instance of MS Word.
foreach (var process in Process.GetProcessesByName("WINWORD"))
{
// Temp is a document which you need to kill.
if (process.MainWindowTitle.Contains("Temp"))
process.Kill();
}
Depending on how many processes there are to kill (e.g. when its hundreds like in my case), foreaching over all of them might take quite a while. (interesting sidenote: while Kill() was usually quite quick in .NET FW 4.8 , somehow in NET 6.0 Windows its a lot slower - seeing multiple Win32Exceptions in the debug/trace until the target process is finally done)
Anyway back to topic:
In case of an app shutdown, where u need to make sure every process is is gone, consider using the TAP library - particulary the Parallel shortcuts, hundreds of processes killed within a glimpse.
Usage example:
var procs = Process.GetProcessByName("mydirtyprocesses");
if (procs.Length == 0) return;
procs.AsParallel().ForAll(process =>
{
try
{
process.Kill();
// No process linked to the process comp (mostly because the process died in
// the short timespan between invoking GetProcess() and the effective
// initialization of the props/fields of the component. -OR- Process has
// already exited (when the exit happened after the process component has
// beenpopulated (difference is, in case 1 you cannot even get the Process
// ID from // the component, in case 2 you see data like Id and get the true
// for HasExited // - so always be prepared for that.
// catch (InvalidOperationException)
{
// Process is gone, no further action required
return;
}
// Ensuring process is gone (otherwise try again or fail or whatever)
if (!process.HasExited)
{
// Handle it
}
}
In this particular scenario just wrap it properly in try/catch , as with such a number of processes the probability for an exception is quite increased
static void Main()
{
string processName = Process.GetCurrentProcess().ProcessName;
int processId = Process.GetCurrentProcess().Id;
Process[] oProcesses = Process.GetProcessesByName(processName);
if (oProcesses.Length > 1)
{
if ((MessageBox.Show("Application is opened!", "",MessageBoxButtons.YesNo) == DialogResult.Yes)) ;
{
foreach (var process in Process.GetProcessesByName(processName))
{
if (process.Id != processId)
{
process.Kill();
}
}
}
}
else
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new frmLogin());
}
}
public void EndTask(string taskname)
{
string processName = taskname.Replace(".exe", "");
foreach (Process process in Process.GetProcessesByName(processName))
{
process.Kill();
}
}
//EndTask("notepad");
Summary: no matter if the name contains .exe, the process will end. You don't need to "leave off .exe from process name", It works 100%.
I have a .NET application that I only allow to run a single process at a time of, however that app is used on Citrix boxes from time to time, and as such, can be run by multiple users on the same machine.
I want to check and make sure that the application is only running once per user session, because right now if user A is running the app, then user B gets the "App already in use" message, and should not.
This is what I have now that checks for the running process:
Process[] p = Process.GetProcessesByName(Process.GetCurrentProcess().ProcessName);
if (p.Length > 1)
{
#if !DEBUG
allowedToOpen &= false;
errorMessage +=
string.Format("{0} is already running.{1}", Constants.AssemblyTitle, Environment.NewLine);
#endif
}
EDIT: Improved the answer according to this cw question ...
You can use a mutex for checking wether the app already runs:
using( var mutex = new Mutex( false, AppGuid ) )
{
try
{
try
{
if( !mutex.WaitOne( 0, false ) )
{
MessageBox.Show( "Another instance is already running." );
return;
}
}
catch( AbandonedMutexException )
{
// Log the fact the mutex was abandoned in another process,
// it will still get aquired
}
Application.Run(new Form1());
}
finally
{
mutex.ReleaseMutex();
}
}
Important is the AppGuid - you could make it depend on the user.
Maybe you like to read this article: the misunderstood mutex
As tanascius already say, you can use the Mutex.
On a server that is running Terminal Services, a named system mutex can have two levels of visibility. If its name begins with the prefix "Global\", the mutex is visible in all terminal server sessions. If its name begins with the prefix "Local\", the mutex is visible only in the terminal server session where it was created.
Source: msdn, Mutex Class
Just stating the obvious - although Mutex is usually considered better solution, you can still solve the single-instance-per-session issue without Mutex - just test the SessionId as well.
private static bool ApplicationIsAlreadyRunning()
{
var currentProcess = Process.GetCurrentProcess();
var processes = Process.GetProcessesByName(currentProcess.ProcessName);
// test if there's another process running in current session.
var intTotalRunningInCurrentSession = processes.Count(prc => prc.SessionId == currentProcess.SessionId);
return intTotalRunningInCurrentSession > 1;
}
Source (no Linq)
If Form1 launches non-background threads, and that Form1 exits, you've got a problem: the mutex is released but the process is still there. Something along the lines below is better IMHO:
static class Program {
private static Mutex mutex;
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main() {
bool createdNew = true;
mutex = new Mutex(true, #"Global\Test", out createdNew);
if (createdNew) {
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new Form1());
}
else {
MessageBox.Show(
"Application is already running",
"Error",
MessageBoxButtons.OK,
MessageBoxIcon.Error
);
}
}
}
The mutex won't be released as long as the primary application domain is still up. And that will be around as long as the application is running.