2010-10-27 2 views
3

L'exemple de code suivant a très bien fonctionné dans Excel 2007, mais lorsque j'installais Excel 2010 (32 bits), le processus excel.exe restait ouvert sauf si j'ajoutais GC.Collect(). Ma question simple est-ce que je fais quelque chose de mal? Il me semble que je libère tout ce que j'utilise.Références de l'objet com Excel 2010 non publiées

public override void Update() 
    { 

     StatusBox.AddStatus("Opening File " + ImportPath); 

     Microsoft.Office.Interop.Excel.Application app = new Microsoft.Office.Interop.Excel.Application(); 
     Microsoft.Office.Interop.Excel.Workbook wb = app.Workbooks.Open(ImportPath, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing); 
     Microsoft.Office.Interop.Excel.Worksheet ws = (Microsoft.Office.Interop.Excel.Worksheet)wb.Sheets[1]; 

     Range rng = ws.Cells.SpecialCells(XlCellType.xlCellTypeLastCell, Type.Missing); 

     int LastRow = rng.Row; 

     StatusBox.AddStatus(LastRow.ToString() + " Rows Found in File"); 


     StatusBox.AddStatus("Closing File " + ImportPath); 

     System.Runtime.InteropServices.Marshal.ReleaseComObject(rng); 
     rng = null; 

     System.Runtime.InteropServices.Marshal.ReleaseComObject(ws); 
     ws = null; 

     wb.Close(true, ImportPath, null); 
     System.Runtime.InteropServices.Marshal.ReleaseComObject(wb); 
     wb = null; 

     GC.Collect(); 

     app.Quit(); 
     System.Runtime.InteropServices.Marshal.ReleaseComObject(app); 
     app = null; 
    } 
+0

Je fais un peu de COM interop avec Excel et MapPoint. Je ne pense pas avoir jamais besoin d'utiliser ReleaseComObject. Effacer toutes les références nulles et appeler les méthodes de fermeture/fermeture appropriées a suffi. Quelqu'un peut-il confirmer/développer le besoin éventuel de ReleaseComObject() dans ces situations de type Office? – winwaed

+0

J'ai ajouté ReleaseComObject quand j'avais des problèmes avec la suspension des références Excel la première fois que j'ai écrit le code pour Excel 2003. J'ai effectivement lu que var = null; pourrait être inutile. –

Répondre

1

Vous devez appeler les deux GC.Collect/GC.WaitForPendingFinalizers et Marshall.FinalReleaseComObject.

Voir ma réponse ici pour plus de détails:

How do I properly clean up Excel interop objects?

Notez que les conseils (et apparemment la réponse plus populaire) dans une commande donnée à « ne jamais utiliser deux points » est valide, mais pratiquement impossible de appliquer dans la pratique. Si vous faites une erreur n'importe où dans votre code, l'application Excel va se bloquer et il n'y a pas d'outil de profilage sur la planète qui peut vous aider - vous devriez revoir tout votre code à la vue. Pour une base de code importante, ceci est essentiellement impossible.

Dans votre code, vous n'avez pas appelé GC.WaitForPendingFinalizers après votre appel à GC.Collect. Cela est nécessaire pour garantir que vos appels de récupération de place sont synchrones. (GC.Collect fonctionne sur un thread différent, si vous ne l'attendez pas, la collection peut se produire dans le désordre par rapport à vos versions d'objet subséquentes et vous voulez libérer des objets COM mineurs, comme Ranges, d'abord, et le principal Les objets COM comme les classeurs et l'application, en dernier.) Après avoir appelé GC.Collect et GC.WaitForPendingFinalizers, vous voudrez alors appeler Marshall.FinalReleaseComObject sur vos références nommées. Donc, en résumé, la stratégie consiste à appeler GC.Collect et GC.WaitForPendingFinalizers pour libérer les objets COM auxquels vous ne possédez pas de référence et appeler Marshall.FinalReleaseComObject pour libérer les objets COM sur lesquels vous tenez un référence nommée.

- Mike

+0

Alors que Hans énumérés correctement si était ma référence à "ws.Cells." c'était le problème (bien que je ne sois pas sûr pourquoi ce n'était pas un problème dans Excel 2007) je marque ceci comme réponse parce que c'est une meilleure explication. Il y a aussi des situations où je pourrais transmettre mes références excel à d'autres bibliothèques, alors que celles-ci sont aussi sous mon contrôle, théoriquement elles ne le sont peut-être pas. –

+0

Heureux que WS.Cells a fait l'affaire, mais, oui, il est étrange que différentes versions d'Excel se comportent différemment ici. Il se pourrait même que la pression mémoire soit différente dans chaque version, de sorte que GC.Collect est implicitement appelé au bon moment plus ou moins par chance dans une version mais pas dans l'autre. Votre discussion sur les bibliothèques tierces, cependant, est le vrai problème - certaines d'entre elles ne libèrent pas leurs références correctement, que votre code interagisse avec elles ou non. Dans ces cas, vous n'avez pas d'autre choix que d'utiliser Process.Kill après avoir appelé Application.Close (ou n'utilisez pas les compléments). –

Questions connexes