Se bloquea la aplicación de instancia única

Este artículo le ayuda a resolver el problema por el que la aplicación de instancia única se bloquea si la aplicación usa WindowsFormsApplicationBase.

Versión original del producto:   Visual C#, Visual Basic.NET
Número de KB original:   2834636

Síntomas

Tiene una única instancia Visual Basic aplicación.NET o una aplicación de C# que usa la WindowsFormsApplicationBase clase para que la aplicación sea una instancia única y que ejecute la aplicación como en un entorno con la virtualización de IP activada. La aplicación puede bloquearse. Si un depurador está asociado a la aplicación, observará que la excepción es CantStartSingleInstanceException.

Causa

Esto se debe a que el Microsoft.VisualBasic.ApplicationServices.WindowsFormsApplicationBase tipo no está diseñado para ejecutarse en un entorno con la virtualización ip activada.

Solución

Para solucionar este problema, puede usar un objeto con nombre mutex o enumerar todos los procesos y ver si se está ejecutando una instancia anterior de la aplicación y activarla.

Código de ejemplo que usa una exclusión mutua con nombre

Nota

Si usa un nombre mutex para limitar la aplicación a una sola instancia, un usuario malintencionado puede crearlo mutex antes de hacerlo e impedir que se inicie la aplicación. Para evitar esta situación, cree un nombre mutex aleatorio y almacene el nombre para que solo lo pueda obtener un usuario autorizado. Como alternativa, puede usar un archivo para este propósito. Para limitar la aplicación a una instancia por usuario, cree un archivo bloqueado en el directorio de perfil del usuario.

  • Código de Visual C#

    public System.Threading.Mutex mutex;
    public void main ()
    {
        bool prevInstance = false;
        mutex = new System.Threading.Mutex (true, 'Application Name', prevInstance);
        if ((prevInstance == false))
        {
            MessageBox.Show ('There is another instance running');   return;  
        }  
        Application.Run (new Form1 ());
    }
    
  • Visual Basic código de .NET

    Public mutex As System.Threading.Mutex
    Public Sub main()
        Dim prevInstance As Boolean
        mutex = New System.Threading.Mutex(True, "Application Name", prevInstance)
        If (prevInstance = False) Then
            MessageBox.Show("There is another instance running")
            Return
        End If
        Application.Run(New Form1())
    End Sub
    

Código de ejemplo que enumera los procesos para ver si se está ejecutando una instancia anterior y la activa

  • Código de Visual C#

    [DllImport ("user32.dll")]
    private static extern int ShowWindow (IntPtr hWnd, int nCmdShow);
    [DllImport ("user32.dll")]
    private static extern int SetForegroundWindow (IntPtr hWnd);
    [DllImport ("user32.dll")]
    private static extern int IsIconic (IntPtr hWnd);
    private const int SW_RESTORE = 9;
    
    /// <summary>
    /// The main entry point for the application.
    /// </summary>
    [STAThread]
    static void Main ()
    {
        var processes = System.Diagnostics.Process.GetProcessesByName ("WindowsFormsApplication1");
        foreach (System.Diagnostics.Process p in processes)
        {
            //Is this the current process?
            if (System.Diagnostics.Process.GetCurrentProcess ().Id == p.Id)
                continue;
            //if the other process is running, we need to activate it and...
            if (null != p.MainWindowHandle)
            {
                if (IsIconic (p.MainWindowHandle) != 0)
                {
                    ShowWindow (p.MainWindowHandle, SW_RESTORE);
                }
                SetForegroundWindow (p.MainWindowHandle);
            }
            //...exit this instance.
            return;
        }
        Application.EnableVisualStyles ();
        Application.SetCompatibleTextRenderingDefault (false);
        Application.Run (new Form1 ());
    }
    
  • Visual Basic código de .NET

    <DllImport("user32.dll")> _
    Private Function ShowWindow(hWnd As IntPtr, nCmdShow As Integer) As Integer
    End Function
    <DllImport("user32.dll")> _
    Private Function SetForegroundWindow(hWnd As IntPtr) As Integer
    End Function
    <DllImport("user32.dll")> _
    Private Function IsIconic(hWnd As IntPtr) As Integer
    End Function
    Private Const SW_RESTORE As Integer = 9
    
    ''' <summary>
    ''' The main entry point for the application.
    ''' </summary>
    <STAThread> _
    Public Sub Main()
        Dim processes = System.Diagnostics.Process.GetProcessesByName("WindowsApplication1")
        For Each p As System.Diagnostics.Process In processes
    
        'Is this the current process?
        If System.Diagnostics.Process.GetCurrentProcess().Id = p.Id Then
            Continue For
        End If
        'if the other process is running, we need to activate it and...
        If p.MainWindowHandle = Nothing Then
        If IsIconic(p.MainWindowHandle) <> 0 Then
            ShowWindow(p.MainWindowHandle, SW_RESTORE)
        End If
    
            SetForegroundWindow(p.MainWindowHandle)
        End If
        '...exit this instance.
        Return
        Next
    
        Application.EnableVisualStyles()
        Application.SetCompatibleTextRenderingDefault(False)
        Application.Run(New Form1())
    End Sub
    

Más información

Para obtener más información, vea Asegurarse de que solo se está ejecutando una única instancia de una aplicación .NET.