Xldotnet : quitter excel sans laisser d'instance en ram

Soyez le premier à donner votre avis sur cette source.

Vue 24 260 fois - Téléchargée 842 fois

Description

En suivant scrupuleusement les recommandations de Microsoft (Q317109) pour libérer les ressources liées à l'automation d'Excel en DotNet... Excel persiste quand même en RAM ! (de l'aveu même de Microsoft).
Le problème est du au caractère non déterministe du collecteur (ramasse-miette ou garbage collector) de la plateforme .Net (et avec l'interopérabilité COM) : personne ne peut vraiment dire quand une ressource sera libérée ; du coup le serveur COM ne peut pas quitter l'instance d'Excel tant que l'appli .Net qui l'a créée (avec CreateObject ou qui y a accéder avec GetObject), et qui possède une référence dessus, reste invisible en RAM : cela va perturber le fonctionnement d'Excel dès la seconde manipulation (si on utilise GetObject, sinon cela ne perturbe pas Excel mais on laisse une nouvelle instance en RAM à chaque appel).
Toutefois, lorsque l'on quitte l'appli .Net, l'instance parasite disparaît automatiquement. Certains affirment qu'en programmant en liaison anticipée (= précoce) via l'interface Office PIA, on peut résoudre ce problème ; cependant cette interface ne fonctionne qu'avec Office XP et 2003, pas avec Office 2000 : la liaison tardive est le seul moyen de cibler toutes les versions d'Excel.
Du coup, la seule solution pour éviter de traîner une instance en RAM est de la tuer purement et simplement (quitte à relancer ensuite Excel de façon indépendante via le fichier créé : voir l'exemple). Pour la tuer il suffit de noter son Id de processus. Or, si l'on peut effectivement retrouver cet Id via le handle d'instance, accessible pour Excel XP et 2003, cette technique ne fonctionne pas pour Excel 2000 (le handle d'instance n'est pas accessible dans ce cas, et le handle de fenêtre ne permet pas de retrouver l'Id processus). Et de plus, ce problème concerne tous les logiciels Office.
J'ai heureusement trouvé sur le web une astuce qui fonctionne à coup sûr : comparer avant et après la liste des processus pour trouver précisément celui que j'ai créé. En conclusion, ce code est donc incontournable pour tout ceux qui veulent cibler aussi Office 2000 en DotNet.

Par Patrice Dargenton

Source / Exemple :


'   clsExcelHost : Classe pour héberger Excel
'   ============

' Title: EXCEL.EXE Process Killer
' Description: After many weeks of trying to figure out why the EXCEL.EXE Process 
'  does not want to go away from the Task Manager, I wrote this class that will ensure 
'  that the correct EXCEL.EXE Process is closed. This is after using Excel.Application 
'  via Automation from a VB.NET/ASP.NET application.
' This file came from Planet-Source-Code.com... the home millions of lines of source code
' You can view comments on this code/and or vote on it at: 
' http://www.Planet-Source-Code.com/vb/scripts/ShowCode.asp?txtCodeId=1998&lngWId=10

' The author may have retained certain copyrights to this code...
'  please observe their request and the law by reviewing all copyright conditions 
'  at the above URL.

'   Author: I.W Coetzer 2004/01/22
'   *Thanks Dan for the process idea.
'   Classe commentée et légèrement modifiée par Patrice Dargenton le 05/11/2004
'   *Solution to the EXCEL.EXE Process that does not want to go away from task manager.
'
'   IMPLEMENTATION (EXAMPLE OF THE CLASS IN USE)
'
'Public Sub TestXL()

'    Dim oXLH As clsExcelHost
'    Try
'        oXLH = New clsExcelHost
'    Catch
'        MsgBox("Excel n'est pas installé !")
'        Exit Sub
'    End Try
'    oXLH.xlApp.Workbooks.Add()
'    oXLH.xlApp.Range("A1") = "Hello World!"
'    oXLH.xlApp.Workbooks(1).SaveAs("C:\Test.xls")
'    oXLH.xlApp.Workbooks(1).Close()
'    oXLH.xlApp.Quit()
'    oXLH.xlApp = Nothing
'    oXLH.Quitter() ' = Process.GetProcessById(xl.ProcId).Kill()
'    oXLH = Nothing
'    MsgBox("C:\Test.xls a été créé avec succès !")
'    Dim p As New Process
'    p.StartInfo = New ProcessStartInfo("C:\Test.xls")
'    p.Start()

'End Sub

Public Class clsExcelHost

    Public xlApp As Object
    Private ProcId%

    Public Sub New()

        ProcId = 0
        ' Liste des processus avant le mien
        Dim Process1() As Process = Process.GetProcesses()
        xlApp = CreateObject("Excel.Application")
        ' Liste des processus après le mien : la différence me donnera l'Id du mien
        Dim Process2() As Process = Process.GetProcesses()

        Dim i%, j%
        Dim bMonProcessXL As Boolean
        For j = 0 To Process2.GetUpperBound(0)
            If Process2(j).ProcessName = "EXCEL" Then
                bMonProcessXL = True
                ' Parcours des processus avant le mien
                For i = 0 To Process1.GetUpperBound(0)
                    If Process1(i).ProcessName = "EXCEL" Then
                        If Process2(j).Id = Process1(i).Id Then
                            ' S'il existait avant, ce n'était pas le mien
                            bMonProcessXL = False
                            Exit For
                        End If
                    End If
                Next i
                If bMonProcessXL = True Then
                    ' Maintenant que j'ai son Id, je pourrai le tuer
                    '  xlApp.Hinstance ne fonctionne pas avec Excel 2000
                    '  alors que cette méthode marche toujours !
                    ProcId = Process2(j).Id
                    Exit For
                End If
            End If
        Next j

    End Sub

    Public Sub Quitter()
        If ProcId = 0 Then Exit Sub
        Process.GetProcessById(ProcId).Kill()
    End Sub

    'Protected Overrides Sub Finalize()
    '    MyBase.Finalize()
    'End Sub

End Class

Conclusion :


Code trouvé ici :
www.Planet-Source-Code.com/vb/scripts/ShowCode.asp?txtCodeId=1998&lngWId=10

Codes Sources

A voir également

Ajouter un commentaire

Commentaires

cs_Patrice99
Messages postés
1222
Date d'inscription
jeudi 23 août 2001
Statut
Membre
Dernière intervention
9 septembre 2018
-
CreateObject permet de faire de la liaison tardive : le code source peut être compilé même si Excel n'est pas installé, et il suffit de trapper l'erreur dans ce cas. Alors qu'utiliser Excel.Application nécessite que Excel soit installé, et à la bonne version qui plus est. Et l'exe ne tournera qu'avec cette version, alors qu'en liaison tardive, la compatibilité ascendante et descendante est assurée (toutes les versions sup. et inf. d'Excel sont supportées, du moment que tu n'appelles pas de fonctionnalité spécifique). L'inconvénient est l'absence de vérification de type à la compilation (mais ça tu peux le faire dans un autre projet de test éventuellement, ou avec des constantes conditionnelles, mais ce n'est certes pas très pratique).
bertatoa
Messages postés
3
Date d'inscription
vendredi 17 février 2006
Statut
Membre
Dernière intervention
21 février 2007
-
tu as raison, j'avais pas compris le code, la seule petite différence, c'est la non utilisation de CreateObject, relicat de vb6, je crois?
Je ferais plus attention la prochaine fois, désolé. :0(
cs_Patrice99
Messages postés
1222
Date d'inscription
jeudi 23 août 2001
Statut
Membre
Dernière intervention
9 septembre 2018
-
Je voulais dire que c'est la meme chose qu'XlDotNet : pas d'API non plus.
bertatoa
Messages postés
3
Date d'inscription
vendredi 17 février 2006
Statut
Membre
Dernière intervention
21 février 2007
-
:o) tout à fait, juste que personnellement j'aime pas trop utiliser les API.
(par rapport au code de Eldim)
ce qui n'engage que moi...
cs_Patrice99
Messages postés
1222
Date d'inscription
jeudi 23 août 2001
Statut
Membre
Dernière intervention
9 septembre 2018
-
C'est strictement la même chose du point de vue fonctionnel.

Vous n'êtes pas encore membre ?

inscrivez-vous, c'est gratuit et ça prend moins d'une minute !

Les membres obtiennent plus de réponses que les utilisateurs anonymes.

Le fait d'être membre vous permet d'avoir un suivi détaillé de vos demandes et codes sources.

Le fait d'être membre vous permet d'avoir des options supplémentaires.