XLDotNet : Quitter
Excel sans laisser d'instance en RAM
https://codes-sources.commentcamarche.net/source/27541
Par Patrice Dargenton
http://patrice.dargenton.free.fr/index.html
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.
'
======================================================================================
' 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