L’application Office ne se ferme pas après l’automatisation à partir du client Visual Studio .NET

S’applique à
Visual Studio 2015

Consultez les autres produits auxquels cet article s’applique.

Symptômes

Lorsque vous automatisez une application Microsoft Office à partir de Microsoft Visual Basic .NET ou de Microsoft Visual C# .NET, l’application Office ne se ferme pas lorsque vous appelez la méthode Quitter.

Cause

Lorsque Visual Studio .NET appelle un objet COM à partir du code managé, il crée automatiquement un wrapper appelable au moment de l’exécution (RCW). Le RCW marshale les appels entre l’application .NET et l’objet COM. Le RCW conserve un nombre de références sur l’objet COM. Par conséquent, si toutes les références n’ont pas été libérées sur le RCW, l’objet COM ne quitte pas.

Résolution

Pour vous assurer que l’application Office se ferme, déterminez si votre code d’automatisation répond aux critères suivants :

  • Déclarez chaque objet en tant que nouvelle variable. Par exemple, modifiez la ligne de code suivante :

    oBook = oExcel.Workbooks.Add()
    
    

    Remplacez ceci par ce qui suit :

    dim oBooks as Excel.Workbooks
    oBooks = oExcel.Workbooks
    oBook = oBooks.Add()
    
    
  • Utilisez System.Runtime.InteropServices.Marshal.ReleaseComObject en boucle jusqu’à ce qu’il renvoie 0 lorsque vous avez fini d’utiliser un objet. System.Runtime.InteropServices.Marshal.ReleaseComObject décrémente le nombre de références du RCW et la boucle s’assure que le composant COM sous-jacent est libéré, quel que soit le nombre de fois qu’il est entré de nouveau dans le CLR.

  • Pour libérer la référence à la variable, donnez-lui la valeur Nothing ou Null.

  • Utilisez la méthode Quitter de l’objet d’application Office pour demander au serveur de s’arrêter.

État

Ce comportement est normal.

Informations supplémentaires

Procédure pour reproduire le comportement

  1. Démarrez Visual Studio .NET.

  2. Dans le menu Fichier, cliquez sur Nouveau, puis sur Projet. Sous Projets Visual Basic, sélectionnez Application Windows, puis cliquez sur OK.

    Remarque Form1 est créé par défaut.

  3. Ajoutez une référence à la bibliothèque d’objets Microsoft Excel. Pour ce faire, procédez comme suit :

    1. Dans le menu Projet, cliquez sur Ajouter une référence.

    2. Sous l’onglet COM, recherchez la bibliothèque d’objets pour Excel, puis cliquez sur Sélectionner.

      Pour Microsoft Excel 2002 : Bibliothèque d’objets Microsoft Excel 10.0

      Remarque Si vous ne l’avez pas déjà fait, nous vous recommandons de télécharger et d’installer les assemblys d’interopérabilité principaux (PIA) Microsoft Office XP.

      Pour plus d’informations sur les PIA d’Office XP, consultez l’article suivant de la Base de connaissances Microsoft :

      328912 les assemblys d’interopérabilité principaux (PIA) Microsoft Office XP sont disponibles au téléchargement
       Pour Microsoft Office Excel 2003 : Bibliothèque d’objets Microsoft Excel 11.0

    3. Cliquez sur OK dans la boîte de dialogue Ajouter des références pour accepter vos sélections.

  4. Dans le menu Affichage, cliquez sur Boîte à outils, puis faites glisser un contrôle de bouton sur le Formulaire 1.

  5. Double-cliquez sur le bouton1.

    Remarque La fenêtre de code du formulaire s’affiche.

  6. Ajoutez le code suivant en haut de Form1.vb :

    Imports Microsoft.Office.Interop
    
    
  7. Remplacez le code suivant dans la fenêtre de code :

        Private Sub Button1_Click(ByVal sender As System.Object, _
           ByVal e As System.EventArgs) Handles Button1.Click
        End Sub
    
    

    Remplacez le code suivant :

    Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
        Dim oApp As New Excel.Application()
        Dim oBook As Excel.Workbook = oApp.Workbooks.Add
        Dim oSheet As Excel.Worksheet = oApp.ActiveSheet
    
        oSheet = Nothing
        oBook.Close(False)
        oBook = Nothing
        oApp.Quit()
        oApp = Nothing
    
        Debug.WriteLine("Sleeping...")
        System.Threading.Thread.Sleep(5000)
        Debug.WriteLine("End Excel")
    End Sub
    
    
  8. Appuyez sur F5 pour exécuter l’application.

  9. Ouvrez le Gestionnaire des tâches Windows. Dans Visual Studio, affichez la fenêtre Sortie pour afficher les messages de débogage. Cliquez sur le bouton de commande. Notez qu’une instance de Excel.exe apparaît dans la liste Processus.

  10. L’instance d’Excel s’exécute toujours dans la liste des tâches, même après la fin de la mise en veille de l’application. Fermez la boîte de dialogue et notez qu’Excel n’apparaît plus dans la liste Processus.

  11. Lorsque vous effectuez les étapes décrites dans la section « Résolution », l’application Office se ferme après avoir libéré la dernière variable. Remplacez la fonction de l’étape 5 par le code suivant :

      Private Sub NAR(ByVal o As Object)
        Try
          While (System.Runtime.InteropServices.Marshal.ReleaseComObject(o) > 0)
          End While
        Catch
        Finally
          o = Nothing
        End Try
      End Sub
    
    Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
        Dim oApp As New Excel.Application()
        Dim oBooks As Excel.Workbooks = oApp.Workbooks
        Dim oBook As Excel.Workbook = oBooks.Add
        Dim oSheet As Excel.Worksheet = oApp.ActiveSheet
    
        NAR(oSheet)
        oBook.Close(False)
        NAR(oBook)
        NAR(oBooks)
        oApp.Quit()
        NAR(oApp)
    
        Debug.WriteLine("Sleeping...")
        System.Threading.Thread.Sleep(5000)
        Debug.WriteLine("End Excel")
    End Sub
    
    

Si vous utilisez Visual C# .NET, reportez-vous au code de la fonction NAR() :


private void NAR(object o)
{
    try 
    {
        while (System.Runtime.InteropServices.Marshal.ReleaseComObject(o) > 0) ;
    }
    catch {}
    finally 
    {
        o = null;
    }
}

Remarque À partir de .NET Framework 2.0, vous pouvez utiliser System.Runtime.InteropServices.Marshal.FinalReleaseComObject au lieu de la boucle while appelant System.Runtime.InteropServices.Marshal.ReleaseComObject pour obtenir le même résultat.
 

Résolution des problèmes

Remarque Si vous suivez les étapes décrites dans la section « Étapes pour reproduire le comportement » et que le serveur ne s’arrête toujours pas, vous pouvez utiliser le GC. collect() et GC. WaitForPendingFinalizers() après avoir libéré le dernier objet. Étant donné que le runtime effectue le nettoyage de la mémoire sur le RCW, le GC. La méthode collect() force le ramasse-miettes à s’exécuter et peut libérer toutes les références que le RCW a encore. Le GC. La méthode Collect() essaie de récupérer le maximum de mémoire disponible. Notez que cela ne garantit pas que toute la mémoire sera récupérée.

S’applique à

Cet article s’applique également aux produits suivants :

  • Microsoft Visual Basic .NET (toutes les éditions)
  • Microsoft Visual C# .NET (toutes les éditions)
  • Microsoft Office 2016 (toutes éditions)
  • Microsoft Office 2013 (toutes éditions)