Usando C # y WPF en .NET (en lugar de Windows Forms o consola), ¿cuál es la forma correcta de crear una aplicación que solo se puede ejecutar como una instancia única?
Sé que tiene algo que ver con algo mítico llamado mutex, rara vez puedo encontrar a alguien que se moleste en detenerse y explicar cuáles son.
El código también debe informar a la instancia que ya se está ejecutando que el usuario intentó iniciar una segunda, y tal vez también pasar cualquier argumento de la línea de comandos si existiera.
Respuestas:
Aquí hay un muy buen artículo sobre la solución Mutex. El enfoque descrito por el artículo es ventajoso por dos razones.
Primero, no requiere una dependencia en el ensamblado Microsoft.VisualBasic. Si mi proyecto ya dependiera de ese ensamblado, probablemente recomendaría usar el enfoque que se muestra en otra respuesta . Pero como es, no uso el ensamblado Microsoft.VisualBasic, y prefiero no agregar una dependencia innecesaria a mi proyecto.
En segundo lugar, el artículo muestra cómo poner en primer plano la instancia existente de la aplicación cuando el usuario intenta iniciar otra instancia. Es un toque muy agradable que las otras soluciones Mutex descritas aquí no abordan.
ACTUALIZAR
A partir del 8/1/2014, el artículo que he vinculado anteriormente aún está activo, pero el blog no se ha actualizado desde hace tiempo. Eso me preocupa de que eventualmente pueda desaparecer, y con ello, la solución recomendada. Estoy reproduciendo el contenido del artículo aquí para la posteridad. Las palabras pertenecen únicamente al propietario del blog en Sanity Free Coding .
fuente
Mutex
constructor simplemente requiere una cadena, por lo que puede proporcionar cualquier nombre de cadena que desee, por ejemplo, "This Is My Mutex". Debido a que un 'Mutex' es un objeto del sistema que está disponible para otros procesos, normalmente desea que el nombre sea único para que no choque con otros nombres 'Mutex' en el mismo sistema. En el artículo, la cadena de aspecto críptico es un 'Guid'. Puede generar esto mediante programación llamandoSystem.Guid.NewGuid()
. En el caso del artículo, el usuario probablemente lo generó a través de Visual Studio como se muestra aquí: msdn.microsoft.com/en-us/library/ms241442(VS.80).aspxPodría usar la clase Mutex, pero pronto descubrirá que necesitará implementar el código para pasar los argumentos y usted mismo. Bueno, aprendí un truco al programar en WinForms cuando leí el libro de Chris Sell . Este truco usa lógica que ya está disponible para nosotros en el marco. No sé sobre ti, pero cuando aprendo sobre cosas que puedo reutilizar en el marco, esa suele ser la ruta que tomo en lugar de reinventar la rueda. A menos que, por supuesto, no haga todo lo que quiero.
Cuando ingresé a WPF, se me ocurrió una manera de usar el mismo código, pero en una aplicación WPF. Esta solución debe satisfacer sus necesidades en función de su pregunta.
Primero, necesitamos crear nuestra clase de aplicación. En esta clase vamos a anular el evento OnStartup y crear un método llamado Activate, que se usará más adelante.
En segundo lugar, necesitaremos crear una clase que pueda administrar nuestras instancias. Antes de pasar por eso, en realidad vamos a reutilizar parte del código que se encuentra en el ensamblado Microsoft.VisualBasic. Como estoy usando C # en este ejemplo, tuve que hacer una referencia al ensamblaje. Si está utilizando VB.NET, no tiene que hacer nada. La clase que vamos a usar es WindowsFormsApplicationBase y heredará nuestro administrador de instancias y luego aprovechará las propiedades y eventos para manejar la instancia única.
Básicamente, estamos utilizando los bits VB para detectar instancias únicas y procesarlas en consecuencia. OnStartup se activará cuando se cargue la primera instancia. OnStartupNextInstance se activa cuando la aplicación se vuelve a ejecutar. Como puede ver, puedo llegar a lo que se pasó en la línea de comando a través de los argumentos del evento. Establecí el valor en un campo de instancia. Puede analizar la línea de comando aquí, o puede pasarla a su aplicación a través del constructor y la llamada al método Activate.
Tercero, es hora de crear nuestro EntryPoint. En lugar de actualizar la aplicación como lo haría normalmente, vamos a aprovechar nuestro SingleInstanceManager.
Bueno, espero que puedas seguir todo y poder usar esta implementación y hacerla tuya.
fuente
A partir de aquí .
Un uso común para un Mutex entre procesos es garantizar que solo se pueda ejecutar una instancia de un programa a la vez. Así es como se hace:
Una buena característica de Mutex es que si la aplicación termina sin que se llame primero a ReleaseMutex, el CLR liberará el Mutex automáticamente.
fuente
MSDN en realidad tiene una aplicación de muestra tanto para C # como para VB para hacer exactamente esto: http://msdn.microsoft.com/en-us/library/ms771662(v=VS.90).aspx
'Another instance of the app is running. Bye'
entonces no será un usuario muy feliz. Simplemente DEBE (en una aplicación GUI) cambiar a esa aplicación y pasar los argumentos proporcionados, o si los parámetros de la línea de comandos no tienen significado, entonces debe abrir la aplicación que puede haber sido minimizada.El marco ya tiene soporte para esto, es solo que un idiota llamó a la DLL
Microsoft.VisualBasic
y no se puso enMicrosoft.ApplicationUtils
o algo así. Supéralo, o abre Reflector.Consejo: Si usa este enfoque exactamente como está, y ya tiene un App.xaml con recursos, etc., también querrá echarle un vistazo .
fuente
Este código debe ir al método principal. Mire aquí para obtener más información sobre el método principal en WPF.
Método 2
Nota: Los métodos anteriores suponen que su proceso / aplicación tiene un nombre único. Porque utiliza el nombre del proceso para buscar si hay procesadores existentes. Entonces, si su aplicación tiene un nombre muy común (es decir: Bloc de notas), el enfoque anterior no funcionará.
fuente
ProcessName
devuelve el nombre del archivo ejecutable menos elexe
. Si crea una aplicación llamada "Bloc de notas" y el bloc de notas de Windows se está ejecutando, lo detectará mientras se ejecuta su aplicación.Bueno, tengo una clase desechable para esto que funciona fácilmente para la mayoría de los casos de uso:
Úselo así:
Aquí está:
fuente
Una nueva aplicación que usa material Mutex e IPC, y también pasa cualquier argumento de línea de comando a la instancia en ejecución, es la Aplicación de instancia única de WPF .
fuente
El código C # .NET Aplicación de instancia única que es la referencia para la respuesta marcada es un gran comienzo.
Sin embargo, descubrí que no maneja muy bien los casos en que la instancia que ya existe tiene un cuadro de diálogo modal abierto, ya sea que ese cuadro de diálogo sea administrado (como otro Formulario, como un cuadro sobre), o no administrado (como el OpenFileDialog incluso cuando se usa la clase estándar .NET). Con el código original, se activa el formulario principal, pero el modal permanece inactivo, lo que parece extraño, además el usuario debe hacer clic en él para seguir usando la aplicación.
Por lo tanto, he creado una clase de utilidad SingleInstance para manejar todo esto de forma bastante automática para Winforms y aplicaciones WPF.
Winforms :
1) modifique la clase del programa de esta manera:
2) modifique la clase de ventana principal de esta manera:
WPF:
1) modifique la página de la aplicación de esta manera (y asegúrese de establecer su acción de compilación en la página para poder redefinir el método Principal):
2) modifique la clase de ventana principal de esta manera:
Y aquí está la clase de utilidad:
fuente
Aquí hay un ejemplo que le permite tener una sola instancia de una aplicación. Cuando se cargan nuevas instancias, pasan sus argumentos a la instancia principal que se está ejecutando.
fuente
Solo algunas reflexiones: hay casos en los que se requiere que solo una instancia de una aplicación no sea "poco convincente", como algunos lo harían creer. Las aplicaciones de bases de datos, etc. son un orden de magnitud más difícil si uno permite que múltiples instancias de la aplicación accedan a una base de datos para un solo usuario (ya sabes, todo eso actualiza todos los registros que están abiertos en múltiples instancias de la aplicación para los usuarios máquina, etc.). Primero, para la "colisión de nombres", no use un nombre legible por humanos - use un GUID en su lugar o, mejor aún, un GUID + el nombre legible por humanos. Las posibilidades de colisión de nombres simplemente desaparecieron del radar y al Mutex no le importa Como alguien señaló, un ataque de DOS sería un asco, pero si la persona maliciosa se ha tomado la molestia de obtener el nombre de mutex e incorporarlo a su aplicación, de todos modos, eres prácticamente un objetivo y tendrás que hacer MUCHO más para protegerte que solo manipular un nombre mutex. Además, si uno usa la variante de: nuevo Mutex (verdadero, "algún GUID más Nombre", fuera AIsFirstInstance), ya tiene su indicador de si el Mutex es o no la primera instancia.
fuente
Tantas respuestas a una pregunta aparentemente tan simple. Solo para sacudir un poco las cosas aquí es mi solución a este problema.
Crear un Mutex puede ser problemático porque el JIT-er solo lo ve usándolo para una pequeña porción de su código y quiere marcarlo como listo para la recolección de basura. Quiere ser más inteligente que pensar que no va a utilizar ese Mutex durante tanto tiempo. En realidad, desea aferrarse a este Mutex mientras su aplicación se esté ejecutando. La mejor manera de decirle al recolector de basura que te deje solo Mutex es decirle que lo mantenga vivo a través de las diferentes generaciones de recolección en el garaje. Ejemplo:
Levanté la idea de esta página: http://www.ai.uga.edu/~mc/SingleInstance.html
fuente
Parece que hay una muy buena manera de manejar esto:
Aplicación de instancia única de WPF
Esto proporciona una clase que puede agregar que administra todos los mutex y mensajes crujientes para simplificar su implementación hasta el punto en que sea simplemente trivial.
fuente
El siguiente código es mi solución de tuberías con nombre WCF para registrar una aplicación de instancia única. Es bueno porque también genera un evento cuando otra instancia intenta iniciarse y recibe la línea de comando de la otra instancia.
Está orientado a WPF porque usa la
System.Windows.StartupEventHandler
clase, pero esto podría modificarse fácilmente.Este código requiere una referencia a
PresentationFramework
, ySystem.ServiceModel
.Uso:
Código fuente:
fuente
Nunca debe usar un mutex con nombre para implementar una aplicación de instancia única (o al menos no para el código de producción). El código malicioso puede fácilmente hacer DoS ( denegación de servicio ) su culo ...
fuente
Mira el siguiente código. Es una solución excelente y simple para evitar múltiples instancias de una aplicación WPF.
fuente
Aquí está lo que uso. Combinó la enumeración de procesos para realizar el cambio y mutex para protegerlos de los "clickers activos":
fuente
Encontré la solución más simple, similar a la de Dale Ragan, pero ligeramente modificada. Hace prácticamente todo lo que necesita y se basa en la clase estándar Microsoft WindowsFormsApplicationBase.
En primer lugar, crea la clase SingleInstanceController, que puede usar en todas las demás aplicaciones de instancia única, que usan Windows Forms:
Luego puede usarlo en su programa de la siguiente manera:
Tanto el programa como la solución SingleInstanceController_NET deben hacer referencia a Microsoft.VisualBasic. Si solo desea reactivar la aplicación en ejecución como una ventana normal cuando el usuario intenta reiniciar el programa en ejecución, el segundo parámetro en SingleInstanceController puede ser nulo. En el ejemplo dado, la ventana está maximizada.
fuente
Actualización 2017-01-25. Después de intentar algunas cosas, decidí usar VisualBasic.dll, es más fácil y funciona mejor (al menos para mí). Dejé mi respuesta anterior solo como referencia ...
Solo como referencia, así es como lo hice sin pasar argumentos (lo cual no puedo encontrar ninguna razón para hacerlo ... me refiero a una sola aplicación con argumentos que se pasan de una instancia a otra). Si se requiere la asociación de archivos, se debe instanciar una aplicación (según la expectativa estándar de los usuarios) para cada documento. Si tiene que pasar argumentos a la aplicación existente, creo que usaría vb dll.
Sin pasar args (solo aplicación de instancia única), prefiero no registrar un nuevo mensaje de Windows y no anular el bucle de mensajes como se define en Matt Davis Solution. Aunque no es un gran problema agregar un dll de VisualBasic, prefiero no agregar una nueva referencia solo para hacer una aplicación de instancia única. Además, prefiero instanciar una nueva clase con Main en lugar de llamar a Shutdown from App. Startupup override para asegurarme de salir lo antes posible.
Con la esperanza de que a alguien le guste ... o inspire un poco :-)
La clase de inicio del proyecto debe establecerse como 'SingleInstanceApp'.
WindowHelper:
fuente
Sin embargo, sin usar Mutex, respuesta simple:
Ponlo dentro del
Program.Main()
.Ejemplo :
Puede agregar
MessageBox.Show
a laif
declaración y poner "La aplicación ya se está ejecutando".Esto podría ser útil para alguien.
fuente
Los enfoques basados en mutex con nombre no son multiplataforma porque los mutex con nombre no son globales en Mono. Los enfoques basados en la enumeración de procesos no tienen ninguna sincronización y pueden dar lugar a un comportamiento incorrecto (por ejemplo, varios procesos iniciados al mismo tiempo pueden terminar automáticamente dependiendo del tiempo). Los enfoques basados en el sistema de ventanas no son deseables en una aplicación de consola. Esta solución, construida sobre la respuesta de Divin, aborda todos estos problemas:
fuente
Uso Mutex en mi solución para prevenir múltiples instancias.
fuente
Utilice la solución mutex:
fuente
Aquí hay una solución liviana que uso que permite que la aplicación traiga una ventana ya existente al primer plano sin recurrir a mensajes personalizados de Windows o buscar ciegamente los nombres de los procesos.
Editar: También puede almacenar e inicializar mutex y createdNew estáticamente, pero deberá deshacerse / liberar explícitamente el mutex una vez que haya terminado con él. Personalmente, prefiero mantener el mutex local, ya que se eliminará automáticamente incluso si la aplicación se cierra sin llegar al final de Main.
fuente
También puede usar CodeFluent Runtime, que es un conjunto gratuito de herramientas. Proporciona una clase SingleInstance para implementar una aplicación de instancia única.
fuente
Agregué un método sendMessage a la clase NativeMethods.
Aparentemente, el método posmensaje no funciona, si la aplicación no se muestra en la barra de tareas, sin embargo, el uso del método sendmessage lo resuelve.
fuente
Aquí está lo mismo implementado a través del evento.
fuente
[He proporcionado un código de muestra para las aplicaciones de consola y wpf a continuación.]
Solo tiene que verificar el valor de
createdNew
variable (¡ejemplo a continuación!), Después de crear la instancia de Mutex con nombre.El booleano
createdNew
devolverá falso:El booleano
createdNew
devolverá verdadero:Aplicación de consola - Ejemplo:
WPF-Ejemplo:
fuente
Una solución que ahorra tiempo para C # Winforms ...
Program.cs:
fuente
Por favor verifique la solución propuesta desde aquí que utiliza un semáforo para determinar si una instancia existente ya se está ejecutando, funciona para una aplicación WPF y puede pasar argumentos de la segunda instancia a la primera instancia que ya se está ejecutando utilizando un TcpListener y un TcpClient:
Funciona también para .NET Core, no solo para .NET Framework.
fuente
No puedo encontrar una solución corta aquí, así que espero que a alguien le guste esto:
ACTUALIZADO 2018-09-20
Pon este código en tu
Program.cs
:fuente