Compartir a través de


Bloqueos de aplicación de instancia única

Este artículo le ayuda a resolver el problema en 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 aplicación de Visual Basic.NET de instancia única o una aplicación de C# que usa la WindowsFormsApplicationBase clase para convertir la instancia única de la aplicación y está ejecutando 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 de IP activada.

Solución

Para solucionar este problema, puede usar un denominado mutex o enumerar todos los procesos y ver si una instancia anterior de la aplicación se está ejecutando 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 y evitar que la aplicación se inicie. Para evitar esta situación, cree un nombre mutex aleatorio y almacene el nombre para que solo pueda obtenerlo 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#

    [STAThread]
    public static void Main()
    {
        bool prevInstance;
        _ = new System.Threading.Mutex(true, "Application Name", out prevInstance);
        if (prevInstance == false)
        {
            MessageBox.Show("There is another instance running");
            return;
        }
        Application.Run(new Form1());
    }
    
  • Código de .NET de Visual Basic

    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 ());
    }
    
  • Código de .NET de Visual Basic

    <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, consulte Asegurarse de que solo se está ejecutando una sola instancia de una aplicación .NET.