En .NET, ¿cuál es la mejor manera de evitar que se ejecuten varias instancias de una aplicación al mismo tiempo? Y si no hay una "mejor" técnica, ¿cuáles son algunas de las advertencias a considerar con cada solución?
En .NET, ¿cuál es la mejor manera de evitar que se ejecuten varias instancias de una aplicación al mismo tiempo? Y si no hay una "mejor" técnica, ¿cuáles son algunas de las advertencias a considerar con cada solución?
Respuestas:
Utiliza Mutex. Uno de los ejemplos anteriores que usa GetProcessByName tiene muchas advertencias. Aquí hay un buen artículo sobre el tema:
http://odetocode.com/Blogs/scott/archive/2004/08/20/401.aspx
[STAThread]
static void Main()
{
using(Mutex mutex = new Mutex(false, "Global\\" + appGuid))
{
if(!mutex.WaitOne(0, false))
{
MessageBox.Show("Instance already running");
return;
}
Application.Run(new Form1());
}
}
private static string appGuid = "c0a76b5a-12ab-45c5-b9d9-d693faa6e7b9";
string appGuid = ((GuidAttribute)Assembly.GetExecutingAssembly().GetCustomAttributes(typeof(GuidAttribute), true)[0]).Value;que obtendrá el guid del ensamblaje ejecutor
if (Process.GetProcessesByName(Process.GetCurrentProcess().ProcessName).Length > 1)
{
AppLog.Write("Application XXXX already running. Only one instance of this application is allowed", AppLog.LogMessageType.Warn);
return;
}
Aquí está el código que necesita para asegurarse de que solo se esté ejecutando una instancia. Este es el método de usar un mutex con nombre.
public class Program
{
static System.Threading.Mutex singleton = new Mutex(true, "My App Name");
static void Main(string[] args)
{
if (!singleton.WaitOne(TimeSpan.Zero, true))
{
//there is already another instance running!
Application.Exit();
}
}
}
Hanselman tiene una publicación sobre el uso de la clase WinFormsApplicationBase del ensamblado Microsoft.VisualBasic para hacer esto.
Parece que hay 3 técnicas fundamentales que se han sugerido hasta ahora.
¿Alguna advertencia que me haya perdido?
1 - Crear una referencia en program.cs ->
using System.Diagnostics;
2 - Poner en void Main()como la primera línea de código ->
if (Process.GetProcessesByName(Process.GetCurrentProcess().ProcessName).Length >1)
return;
Eso es.
Mutex? ¿Hay alguna trampa?
Usando Visual Studio 2005 o 2008 cuando crea un proyecto para un ejecutable, en las ventanas de propiedades dentro del panel "Aplicación" hay una casilla de verificación llamada "Crear aplicación de instancia única" que puede activar para convertir la aplicación en una aplicación de instancia única .
Aquí hay una captura de la ventana de la que estoy hablando:
Este es un proyecto de aplicación de Windows de Visual Studio 2008.
Probé todas las soluciones aquí y nada funcionó en mi proyecto C # .net 4.0. Con la esperanza de ayudar a alguien aquí, la solución que funcionó para mí:
Como principales variables de clase:
private static string appGuid = "WRITE AN UNIQUE GUID HERE";
private static Mutex mutex;
Cuando necesite verificar si la aplicación ya se está ejecutando:
bool mutexCreated;
mutex = new Mutex(true, "Global\\" + appGuid, out mutexCreated);
if (mutexCreated)
mutex.ReleaseMutex();
if (!mutexCreated)
{
//App is already running, close this!
Environment.Exit(0); //i used this because its a console app
}
Necesitaba cerrar otras istances solo con algunas condiciones, esto funcionó bien para mi propósito
http://en.csharp-online.net/Application_Architecture_in_Windows_Forms_2.0 — Single-Instance_Detection_and_Management
Después de probar varias soluciones, la pregunta. Terminé usando el ejemplo para WPF aquí: http://www.c-sharpcorner.com/UploadFile/f9f215/how-to-restrict-the-application-to-just-one-instance/
public partial class App : Application
{
private static Mutex _mutex = null;
protected override void OnStartup(StartupEventArgs e)
{
const string appName = "MyAppName";
bool createdNew;
_mutex = new Mutex(true, appName, out createdNew);
if (!createdNew)
{
//app is already running! Exiting the application
Application.Current.Shutdown();
}
}
}
En App.xaml:
x:Class="*YourNameSpace*.App"
StartupUri="MainWindow.xaml"
Startup="App_Startup"
Este artículo simplemente explica cómo puede crear una aplicación de Windows con control sobre el número de instancias o ejecutar solo una instancia. Esta es una necesidad muy típica de una aplicación comercial. Ya hay muchas otras posibles soluciones para controlar esto.
http://www.openwinforms.com/single_instance_application.html
Este es el código para VB.Net
Private Shared Sub Main()
Using mutex As New Mutex(False, appGuid)
If Not mutex.WaitOne(0, False) Then
MessageBox.Show("Instance already running", "ERROR", MessageBoxButtons.OK, MessageBoxIcon.Error)
Return
End If
Application.Run(New Form1())
End Using
End Sub
Este es el código para C #
private static void Main()
{
using (Mutex mutex = new Mutex(false, appGuid)) {
if (!mutex.WaitOne(0, false)) {
MessageBox.Show("Instance already running", "ERROR", MessageBoxButtons.OK, MessageBoxIcon.Error);
return;
}
Application.Run(new Form1());
}
}
Tienes que usar System.Diagnostics.Process.
Echa un vistazo: http://www.devx.com/tips/Tip/20044
(Nota: ¡esta es una solución divertida! Funciona pero utiliza un mal diseño GDI + para lograrlo).
Coloque una imagen con su aplicación y cárguela al inicio. Sosténgalo hasta que salga la aplicación. El usuario no podrá iniciar una segunda instancia. (Por supuesto, la solución mutex es mucho más limpia)
private static Bitmap randomName = new Bitmap("my_image.jpg");
Main()método que vaya en contra de cómo se supone que funciona WPF.
[STAThread]
static void Main() // args are OK here, of course
{
bool ok;
m = new System.Threading.Mutex(true, "YourNameHere", out ok);
if (! ok)
{
MessageBox.Show("Another instance is already running.");
return;
}
Application.Run(new Form1()); // or whatever was there
GC.KeepAlive(m); // important!
}
De: Asegurar una única instancia de aplicación .NET
y: Aplicación de instancia única Mutex
Misma respuesta que @Smink y @Imjustpondering con un toque:
Preguntas frecuentes de Jon Skeet sobre C # para descubrir por qué GC.KeepAlive es importante
Simplemente usando a StreamWriter, ¿qué tal esto?
System.IO.File.StreamWriter OpenFlag = null; //globally
y
try
{
OpenFlag = new StreamWriter(Path.GetTempPath() + "OpenedIfRunning");
}
catch (System.IO.IOException) //file in use
{
Environment.Exit(0);
}
Normalmente se realiza con un Mutex con nombre (use un nuevo Mutex ("nombre de su aplicación", verdadero) y verifique el valor de retorno), pero también hay algunas clases de soporte en Microsoft.VisualBasic.dll que pueden hacerlo por usted .
Esto funcionó para mí en C # puro. el intento / captura es cuando posiblemente un proceso en la lista salga durante su ciclo.
using System.Diagnostics;
....
[STAThread]
static void Main()
{
...
int procCount = 0;
foreach (Process pp in Process.GetProcesses())
{
try
{
if (String.Compare(pp.MainModule.FileName, Application.ExecutablePath, true) == 0)
{
procCount++;
if(procCount > 1) {
Application.Exit();
return;
}
}
}
catch { }
}
Application.Run(new Form1());
}
Asegúrese de tener en cuenta la seguridad al restringir una aplicación a una sola instancia:
Artículo completo: https://blogs.msdn.microsoft.com/oldnewthing/20060620-13/?p=30813
Estamos utilizando un mutex con nombre con un nombre fijo para detectar si se está ejecutando otra copia del programa. Pero eso también significa que un atacante puede crear el mutex primero, ¡evitando así que nuestro programa se ejecute! ¿Cómo puedo evitar este tipo de ataque de denegación de servicio?
...
Si el atacante se ejecuta en el mismo contexto de seguridad en el que se ejecuta (o estaría) su programa, entonces no hay nada que pueda hacer. Cualquiera sea el "apretón de manos secreto" que se le ocurra para determinar si se está ejecutando otra copia de su programa, el atacante puede imitarlo. Como se ejecuta en el contexto de seguridad correcto, puede hacer cualquier cosa que el programa "real" pueda hacer.
...
Claramente, no puede protegerse de un atacante que se ejecuta con el mismo privilegio de seguridad, pero aún puede protegerse contra los atacantes no privilegiados que se ejecutan con otros privilegios de seguridad.
Intente configurar un DACL en su mutex, aquí está la forma .NET: https://msdn.microsoft.com/en-us/library/system.security.accesscontrol.mutexsecurity(v=vs.110).aspx
Ninguna de estas respuestas funcionó para mí porque necesitaba que esto funcionara bajo Linux usando monodevelop. Esto funciona muy bien para mí:
Llame a este método pasándole una identificación única
public static void PreventMultipleInstance(string applicationId)
{
// Under Windows this is:
// C:\Users\SomeUser\AppData\Local\Temp\
// Linux this is:
// /tmp/
var temporaryDirectory = Path.GetTempPath();
// Application ID (Make sure this guid is different accross your different applications!
var applicationGuid = applicationId + ".process-lock";
// file that will serve as our lock
var fileFulePath = Path.Combine(temporaryDirectory, applicationGuid);
try
{
// Prevents other processes from reading from or writing to this file
var _InstanceLock = new FileStream(fileFulePath, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.None);
_InstanceLock.Lock(0, 0);
MonoApp.Logger.LogToDisk(LogType.Notification, "04ZH-EQP0", "Aquired Lock", fileFulePath);
// todo investigate why we need a reference to file stream. Without this GC releases the lock!
System.Timers.Timer t = new System.Timers.Timer()
{
Interval = 500000,
Enabled = true,
};
t.Elapsed += (a, b) =>
{
try
{
_InstanceLock.Lock(0, 0);
}
catch
{
MonoApp.Logger.Log(LogType.Error, "AOI7-QMCT", "Unable to lock file");
}
};
t.Start();
}
catch
{
// Terminate application because another instance with this ID is running
Environment.Exit(102534);
}
}