Duda - Como restringir la aplicacion a una instancia?

Iniciado por OscarCadenas_91, 22 Febrero 2018, 18:08 PM

0 Miembros y 2 Visitantes están viendo este tema.

OscarCadenas_91

buenas queria preguntarles cual es la forma mas adecuada a hacer esto, basicamente es que tengo una aplicacion hecha en vb.net winform y que lee archivos csv, la aplicacion esta asociada a la extension es decir que  al hacer doble clic sobre el archivo inicia y carga el contenido en mi aplicación, uno de los detalles es que si quiero abrir otro archivo se me abre la aplicacion otra ves y lo que quiero es que se abra solo en una.

Estaba leyendo por internet que esto se puede hacer mediante:

1) la api "SendMessage" es decir al iniciar y comprobar si el proceso esta activo y si lo esta  enviar los archivos que pasan Environment.GetCommandLineArgs()
y luego cerrar la aplicacion.
2)lo mismo que el anterior solo que en ves de verificar si el proceso esta activo usar MUTEX.
3)Hacerlo mediante el WindowsFormsApplicationBase, es decir   heredar una clase de WindowsFormsApplicationBase  estableciendo la propiedad IsSingleInstance  en TRUE.
4) Mediante: Dynamic Data Exchange (DDE) - (Esto si que no tengo mucha idea)

Cual de estas formas deberia usar??


Gracias

Eleкtro

#1
Cita de: OscarCadenas_91 en 22 Febrero 2018, 18:08 PM
Duda - Como restringir la aplicacion a una instancia? 

Solo tienes que hacer un simple click en esta casilla...



Si estuvieramos hablando de C# entonces la cosa cambiaría, ya que a Microsoft y los devs. de Visual Studio les gusta complicarle la vida a los que programan en C#, jeje, lo apropiado sería crear (y apropiarse de) un MUTEX usando la clase Mutex.

Saludos!








OscarCadenas_91

muchas gracias por responder

pero aun me queda por resolver como capturar el archivo que intento abrir es decir ya no se abre otra ves pero no puedo obtener el nuevo archivo que intento abrir en mi aplicacion


Eleкtro

#3
Cita de: OscarCadenas_91 en 23 Febrero 2018, 00:59 AM
pero aun me queda por resolver como capturar el archivo que intento abrir es decir ya no se abre otra ves pero no puedo obtener el nuevo archivo que intento abrir en mi aplicacion

Pensé que ya sabrías como. Puedes usar cualquier tipo de intercomunicación entre procesos (IPC) como por ejemplo MMF (memory mapped file) para compartir un bloque de memoria entre tus procesos y escribir los argumentos recibidos en el stream, o iguálmente lo puedes hacer con una named pipe, o con un socket si me apuras. Tambien puedes usar la clase EventWaitHandle para crear un 'semáforo' global entre tus procesos, aunque ello implicaría la necesidad de adaptar tu código para volverlo asíncrono (ya que la idea sería detener la ejecución de un thread y enviar una señal de reanudación al iniciar la próxima instancia de tu aplicación con los nuevos argumentos). En fin, formas de hacerlo hay muchas. Yo lo que considero más simple para este escenario en concreto sería declarar una clase que implemente la interfaz INotifyPropertyChanged, y listo.

Te muestro un ejemplo completo mediante la implementación de INotifyPropertyChanged:

CommandLineNotifier.vb
Código (vbnet) [Seleccionar]
Imports System.Collections.ObjectModel
Imports System.ComponentModel
Imports System.Runtime.CompilerServices

Public Class CommandLineNotifier : Implements INotifyPropertyChanged

   Public Property Arguments As ReadOnlyCollection(Of String)
       Get
           Return Me.argumentsB
       End Get
       Set(ByVal value As ReadOnlyCollection(Of String))
           If (value.Any()) AndAlso Not (value.Equals(Me.argumentsB)) Then
               Me.argumentsB = value
               Me.NotifyPropertyChanged()
           End If
       End Set
   End Property
   Private argumentsB As ReadOnlyCollection(Of String)

   Private Event PropertyChanged As PropertyChangedEventHandler Implements INotifyPropertyChanged.PropertyChanged
   Public Shared Event ArgumentsReceived As EventHandler(Of ReadOnlyCollection(Of String))

   Public Sub New(ByVal notifyCurrentArguments As Boolean)
       If (notifyCurrentArguments) Then
           Me.Arguments = New ReadOnlyCollection(Of String)(Environment.GetCommandLineArgs().Skip(1).ToArray())
       End If
   End Sub

   Private Sub NotifyPropertyChanged(<CallerMemberName> Optional ByVal propertyName As String = Nothing)
       RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs(propertyName))
   End Sub

   Private Sub CommandLineNotifier_PropertyChanged(sender As Object, e As PropertyChangedEventArgs) _
   Handles Me.PropertyChanged

       Select Case (e.PropertyName)

           Case NameOf(Arguments)
               If (CommandLineNotifier.ArgumentsReceivedEvent IsNot Nothing) Then
                   RaiseEvent ArgumentsReceived(Me, Me.argumentsB)
               End If

           Case Else
               Throw New NotImplementedException()

       End Select

   End Sub

End Class


ApplicationEvents.vb (la clase donde se controlan los eventos de la aplicación)
Código (vbnet) [Seleccionar]
Imports Microsoft.VisualBasic.ApplicationServices

Namespace My

   Partial Friend Class MyApplication

       Public Shared CommandLineNotifier As CommandLineNotifier

       Public Sub MyApplication_StartupNextInstance(sender As Object, e As StartupNextInstanceEventArgs) Handles Me.StartupNextInstance
           If (e.CommandLine.Any) Then
               My.MyApplication.CommandLineNotifier.Arguments = e.CommandLine
           End If
       End Sub

   End Class

End Namespace


Form1.vb
Código (vbnet) [Seleccionar]
Imports System.Collections.ObjectModel

Public Class Form1

   Public Sub New()
       MyClass.InitializeComponent()
       AddHandler CommandLineNotifier.ArgumentsReceived, AddressOf Me.CommandLineNotifier_ArgumentsReceived
       My.MyApplication.CommandLineNotifier = New CommandLineNotifier(notifyCurrentArguments:=True)
   End Sub

   Public Sub CommandLineNotifier_ArgumentsReceived(sender As Object, e As ReadOnlyCollection(Of String))
       ' En este ejemplo añado los nuevos argumentos recibidos, a un ListBox.
       Me.ListBox1.Items.AddRange(DirectCast(sender, CommandLineNotifier).Arguments.ToArray())
   End Sub

End Class


Saludos.








OscarCadenas_91

 Muchisimas gracias elektro era justo lo que necesitaba  ;-) , gracias por tomarte el tiempo en ayudarme. 


Salu2 :D