Blocage de l’application à instance unique

Cet article vous aide à résoudre le problème où l’application à instance unique se bloque si l’application utilise WindowsFormsApplicationBase.

Version du produit d’origine : Visual C#, Visual Basic.NET
Numéro de base de connaissances d’origine : 2834636

Symptômes

Vous avez une seule instance Visual Basic.NET application ou une application C# qui utilise la WindowsFormsApplicationBase classe pour rendre l’instance unique de l’application et vous exécutez l’application comme dans un environnement avec IP Virtualization activée. L’application peut se bloquer. si un débogueur est attaché à l’application, vous remarquerez que l’exception est CantStartSingleInstanceException.

Cause

Cela est dû au fait que le Microsoft.VisualBasic.ApplicationServices.WindowsFormsApplicationBase type n’est pas conçu pour s’exécuter dans un environnement avec la virtualisation IP activée.

Résolution

Pour contourner ce problème, vous pouvez utiliser un nom mutex ou énumérer tous les processus et voir si une instance précédente de l’application est en cours d’exécution et l’active.

Exemple de code qui utilise un mutex nommé

Note

Si vous utilisez un nom mutex pour limiter votre application à une seule instance, un utilisateur malveillant peut le créer mutex avant de commencer et empêcher votre application de démarrer. Pour éviter cette situation, créez un nom aléatoire mutex et stockez le nom afin qu’il puisse uniquement être obtenu par un utilisateur autorisé. Vous pouvez également utiliser un fichier à cet effet. Pour limiter votre application à une instance par utilisateur, créez un fichier verrouillé dans le répertoire de profil de l’utilisateur.

  • Code 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());
    }
    
  • Code .NET 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
    

Exemple de code qui énumère les processus pour voir si une instance précédente est en cours d’exécution et l’active

  • Code 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 ());
    }
    
  • Code .NET 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
    

Plus d’informations

Pour plus d’informations, consultez Vérifier que seule une seule instance d’une application .NET est en cours d’exécution.