J'utilise l'interopérabilité Excel en C # ( ApplicationClass
) et j'ai placé le code suivant dans ma clause finally:
while (System.Runtime.InteropServices.Marshal.ReleaseComObject(excelSheet) != 0) { }
excelSheet = null;
GC.Collect();
GC.WaitForPendingFinalizers();
Bien que ce genre de travaux, le Excel.exe
processus est toujours en arrière-plan même après avoir fermé Excel. Il n'est publié que lorsque ma candidature est fermée manuellement.
Que fais-je de mal ou existe-t-il une alternative pour garantir que les objets d'interopérabilité sont correctement éliminés?
c#
excel
interop
com-interop
Enfers
la source
la source
Réponses:
Excel ne se ferme pas car votre application contient toujours des références à des objets COM.
Je suppose que vous invoquez au moins un membre d'un objet COM sans l'assigner à une variable.
Pour moi, c'était l' objet excelApp.Worksheets que j'ai directement utilisé sans l'assigner à une variable:
Je ne savais pas qu'en interne C # avait créé un wrapper pour l' objet Worksheets COM qui n'était pas libéré par mon code (parce que je ne le savais pas) et était la raison pour laquelle Excel n'était pas déchargé.
J'ai trouvé la solution à mon problème sur cette page , qui a également une bonne règle pour l'utilisation des objets COM en C #:
Donc, avec cette connaissance, la bonne façon de faire ce qui précède est:
MISE À JOUR POST MORTEM:
Je veux que chaque lecteur lise très attentivement cette réponse de Hans Passant car elle explique le piège dans lequel je suis tombé et beaucoup d'autres développeurs. Lorsque j'ai écrit cette réponse il y a des années, je ne connaissais pas l'effet du débogueur sur le garbage collector et j'ai tiré des conclusions erronées. Je garde ma réponse inchangée pour le bien de l'histoire mais s'il vous plaît lisez ce lien et n'allez pas dans le sens des "deux points": Comprendre le garbage collection dans .NET et nettoyer les objets Interop Excel avec IDisposable
la source
Vous pouvez réellement libérer votre objet Application Excel proprement, mais vous devez faire attention.
Le conseil de conserver une référence nommée pour absolument chaque objet COM auquel vous accédez et de le libérer explicitement via
Marshal.FinalReleaseComObject()
est correct en théorie, mais malheureusement très difficile à gérer dans la pratique. Si quelqu'un glisse quelque part et utilise "deux points", ou itère des cellules via unefor each
boucle, ou tout autre type de commande similaire, alors vous aurez des objets COM non référencés et risquerez un blocage. Dans ce cas, il n'y aurait aucun moyen de trouver la cause dans le code; vous devrez revoir tout votre code à l'œil nu et, espérons-le, trouver la cause, une tâche qui pourrait être presque impossible pour un grand projet.La bonne nouvelle est que vous n'avez pas réellement besoin de conserver une référence de variable nommée à chaque objet COM que vous utilisez. Au lieu de cela, appelez
GC.Collect()
puisGC.WaitForPendingFinalizers()
libérez tous les objets (généralement mineurs) auxquels vous ne détenez pas de référence, puis libérez explicitement les objets auxquels vous détenez une référence de variable nommée.Vous devez également libérer vos références nommées dans l'ordre inverse de leur importance: les objets de plage d'abord, puis les feuilles de calcul, les classeurs, puis enfin votre objet Application Excel.
Par exemple, en supposant que vous disposiez d'une variable d'objet Range nommée
xlRng
, d'une variable de feuille de calcul nomméexlSheet
, d'une variable de classeur nomméexlBook
et d'une variable d'application Excel nomméexlApp
, votre code de nettoyage pourrait ressembler à ceci:Dans la plupart des exemples de code que vous verrez pour nettoyer les objets COM de .NET, les appels
GC.Collect()
etGC.WaitForPendingFinalizers()
sont effectués DEUX FOIS comme dans:Cela ne devrait toutefois pas être requis, sauf si vous utilisez Visual Studio Tools pour Office (VSTO), qui utilise des finaliseurs qui provoquent la promotion d'un graphique entier d'objets dans la file d'attente de finalisation. Ces objets ne seront pas libérés avant la prochaine collecte de place. Cependant, si vous n'utilisez pas VSTO, vous devriez pouvoir appeler
GC.Collect()
etGC.WaitForPendingFinalizers()
une seule fois.Je sais qu'appeler explicitement
GC.Collect()
est un non-non (et le faire deux fois semble très douloureux), mais il n'y a aucun moyen de contourner cela, pour être honnête. Grâce à des opérations normales, vous générerez des objets cachés auxquels vous ne détenez aucune référence que vous ne pouvez donc pas libérer par d'autres moyens que l'appelGC.Collect()
.C'est un sujet complexe, mais c'est vraiment tout ce qu'il y a à faire. Une fois que vous avez établi ce modèle pour votre procédure de nettoyage, vous pouvez coder normalement, sans avoir besoin de wrappers, etc. :-)
J'ai un tutoriel à ce sujet ici:
Automatisation des programmes Office avec VB.Net / COM Interop
Il est écrit pour VB.NET, mais ne soyez pas rebuté par cela, les principes sont exactement les mêmes que lors de l'utilisation de C #.
la source
Préface: ma réponse contient deux solutions, alors soyez prudent lors de la lecture et ne manquez rien.
Il existe différentes manières et conseils pour effectuer le déchargement d'instance Excel, tels que:
Libération de CHAQUE objet com explicitement avec Marshal.FinalReleaseComObject () (sans oublier les objets com créés implicitement). Pour libérer chaque objet com créé, vous pouvez utiliser la règle des 2 points mentionnés ici:
Comment nettoyer correctement les objets d'interopérabilité Excel?
Appel de GC.Collect () et GC.WaitForPendingFinalizers () pour que CLR libère des objets com inutilisés * (En fait, cela fonctionne, voir ma deuxième solution pour plus de détails)
Vérifier si l'application com-server affiche peut-être une boîte de message attendant que l'utilisateur réponde (bien que je ne suis pas sûr que cela puisse empêcher Excel de se fermer, mais j'en ai entendu parler plusieurs fois)
Envoi d'un message WM_CLOSE à la fenêtre principale d'Excel
Exécution de la fonction qui fonctionne avec Excel dans un AppDomain distinct. Certaines personnes pensent que l'instance Excel sera fermée lorsque AppDomain sera déchargé.
Tuer toutes les instances Excel qui ont été instanciées après le début de notre code d'interaction Excel.
MAIS! Parfois, toutes ces options ne sont tout simplement pas utiles ou ne peuvent pas être appropriées!
Par exemple, hier, j'ai découvert que dans l'une de mes fonctions (qui fonctionne avec Excel), Excel continue de fonctionner après la fin de la fonction. J'ai tout essayé! J'ai soigneusement vérifié l'ensemble de la fonction 10 fois et ajouté Marshal.FinalReleaseComObject () pour tout! J'ai également eu GC.Collect () et GC.WaitForPendingFinalizers (). J'ai vérifié les boîtes de message cachées. J'ai essayé d'envoyer un message WM_CLOSE à la fenêtre principale d'Excel. J'ai exécuté ma fonction dans un AppDomain distinct et déchargé ce domaine. Rien n'a aidé! L'option de fermeture de toutes les instances Excel est inappropriée, car si l'utilisateur démarre une autre instance Excel manuellement, lors de l'exécution de ma fonction qui fonctionne également avec Excel, cette instance sera également fermée par ma fonction. Je parie que l'utilisateur ne sera pas content! Donc, honnêtement, c'est une option boiteuse (pas de gars offensifs).solution : Tuez le processus Excel par hWnd de sa fenêtre principale (c'est la première solution).
Voici le code simple:
Comme vous pouvez le voir, j'ai fourni deux méthodes, selon le modèle Try-Parse (je pense que c'est approprié ici): une méthode ne lève pas l'exception si le processus n'a pas pu être tué (par exemple, le processus n'existe plus) et une autre méthode lève l'exception si le processus n'a pas été tué. Le seul point faible dans ce code est les autorisations de sécurité. Théoriquement, l'utilisateur peut ne pas avoir l'autorisation de tuer le processus, mais dans 99,99% de tous les cas, l'utilisateur a de telles autorisations. Je l'ai également testé avec un compte invité - cela fonctionne parfaitement.
Ainsi, votre code, en travaillant avec Excel, peut ressembler à ceci:
Voila! Excel est terminé! :)
Ok, revenons à la deuxième solution, comme je l'ai promis au début de l'article. La deuxième solution consiste à appeler GC.Collect () et GC.WaitForPendingFinalizers (). Oui, ils fonctionnent réellement, mais vous devez faire attention ici!
Beaucoup de gens disent (et j'ai dit) qu'appeler GC.Collect () n'aide pas. Mais la raison pour laquelle cela n'aiderait pas est qu'il existe encore des références aux objets COM! L'une des raisons les plus courantes pour lesquelles GC.Collect () n'est pas utile est d'exécuter le projet en mode débogage. En mode débogage, les objets qui ne sont plus vraiment référencés ne seront pas récupérés jusqu'à la fin de la méthode.
Donc, si vous avez essayé GC.Collect () et GC.WaitForPendingFinalizers () et que cela n'a pas aidé, essayez de faire ce qui suit:
1) Essayez d'exécuter votre projet en mode Release et vérifiez si Excel s'est bien fermé
2) Enveloppez la méthode de travail avec Excel dans une méthode distincte. Donc, au lieu de quelque chose comme ça:
vous écrivez:
Maintenant, Excel fermera =)
la source
MISE À JOUR : Code C # ajouté et lien vers les travaux Windows
J'ai passé quelque temps à essayer de comprendre ce problème, et à l'époque XtremeVBTalk était le plus actif et le plus réactif. Voici un lien vers mon article d'origine, Fermer un processus Excel Interop proprement, même si votre application se bloque . Vous trouverez ci-dessous un résumé du message et le code copié dans ce message.
Application.Quit()
etProcess.Kill()
fonctionne pour la plupart, mais échoue si les applications se bloquent de manière catastrophique. Autrement dit, si l'application se bloque, le processus Excel sera toujours en cours d'exécution.J'ai trouvé que c'était une solution propre parce que le système d'exploitation faisait un vrai travail de nettoyage. Il vous suffit d' enregistrer le processus Excel.
Code de travail Windows
Encapsule les appels API Win32 pour enregistrer les processus Interop.
Remarque sur le code constructeur
info.LimitFlags = 0x2000;
est appelé.0x2000
est laJOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE
valeur énumérée, et cette valeur est définie par MSDN comme:Appel API Win32 supplémentaire pour obtenir l'ID de processus (PID)
Utiliser le code
la source
Cela a fonctionné pour un projet sur lequel je travaillais:
Nous avons appris qu'il était important de définir chaque référence à un objet COM Excel sur null lorsque vous en avez terminé. Cela comprenait les cellules, les feuilles et tout le reste.
la source
Tout ce qui se trouve dans l'espace de noms Excel doit être libéré. Période
Vous ne pouvez pas faire:
Vous devez faire
suivi de la libération des objets.
la source
Tout d'abord - vous n'avez jamais à appeler
Marshal.ReleaseComObject(...)
ouMarshal.FinalReleaseComObject(...)
à faire de l'interopérabilité Excel. Il s'agit d'un anti-modèle déroutant, mais toute information à ce sujet, y compris de Microsoft, qui indique que vous devez libérer manuellement les références COM à partir de .NET est incorrecte. Le fait est que le runtime .NET et le garbage collector conservent et nettoient correctement les références COM. Pour votre code, cela signifie que vous pouvez supprimer la boucle `while (...) en haut.Deuxièmement, si vous souhaitez vous assurer que les références COM à un objet COM hors processus sont nettoyées à la fin de votre processus (afin que le processus Excel se ferme), vous devez vous assurer que le garbage collector s'exécute. Vous faites cela correctement avec les appels à
GC.Collect()
etGC.WaitForPendingFinalizers()
. Appeler cela deux fois est sûr et garantit que les cycles sont définitivement nettoyés aussi (bien que je ne sois pas sûr que ce soit nécessaire, et j'apprécierais un exemple qui le montre).Troisièmement, lors de l'exécution sous le débogueur, les références locales seront maintenues artificiellement en vie jusqu'à la fin de la méthode (pour que l'inspection des variables locales fonctionne). Les
GC.Collect()
appels ne sont donc pas efficaces pour nettoyer un objet comme àrng.Cells
partir de la même méthode. Vous devez diviser le code effectuant l'interopérabilité COM du nettoyage du GC en méthodes distinctes. (Ce fut une découverte clé pour moi, à partir d'une partie de la réponse publiée ici par @nightcoder.)Le schéma général serait donc:
Il y a beaucoup de fausses informations et de confusion sur ce problème, y compris de nombreux messages sur MSDN et sur Stack Overflow (et surtout cette question!).
Ce qui m'a finalement convaincu de regarder de plus près et de trouver le bon conseil, c'est le blog Marshal.ReleaseComObject Considéré dangereux, ainsi que de trouver le problème avec des références maintenues en vie sous le débogueur qui confondait mes tests précédents.
la source
J'ai trouvé un modèle générique utile qui peut aider à implémenter le modèle d'élimination correct pour les objets COM, qui ont besoin de Marshal.ReleaseComObject appelé lorsqu'ils sortent du domaine:
Usage:
Modèle:
Référence:
http://www.deez.info/sengelha/2005/02/11/useful-idisposable-class-3-autoreleasecomobject/
la source
Je ne peux pas croire que ce problème hante le monde depuis 5 ans ... Si vous avez créé une application, vous devez la fermer avant de supprimer le lien.
à la fermeture
Lorsque vous créez une nouvelle application Excel, elle ouvre un programme Excel en arrière-plan. Vous devez commander à ce programme Excel de se fermer avant de libérer le lien, car ce programme Excel ne fait pas partie de votre contrôle direct. Par conséquent, il restera ouvert si le lien est libéré!
Bonne programmation tout le monde ~~
la source
Développeurs communs, aucune de vos solutions n'a fonctionné pour moi, alors je décide de mettre en œuvre une nouvelle astuce .
Précisons d'abord "Quel est notre objectif?" => "Ne pas voir l'objet Excel après notre travail dans le gestionnaire de tâches"
D'accord. Laissez no le contester et commencez à le détruire, mais pensez à ne pas détruire les autres instances d'OS Excel qui s'exécutent en parallèle.
Donc, obtenez la liste des processeurs actuels et récupérez le PID des processus EXCEL, puis une fois votre travail terminé, nous avons un nouvel invité dans la liste des processus avec un PID unique, trouvez et détruisez juste celui-là.
<gardez à l'esprit que tout nouveau processus Excel au cours de votre travail Excel sera détecté comme nouveau et détruit> <Une meilleure solution consiste à capturer le PID du nouvel objet Excel créé et à le détruire>
Cela résout mon problème, j'espère que le vôtre aussi.
la source
Cela semble bien sûr trop compliqué. D'après mon expérience, il n'y a que trois éléments clés pour que Excel se ferme correctement:
1: assurez-vous qu'il ne reste aucune référence à l'application Excel que vous avez créée (vous ne devriez en avoir qu'une de toute façon; définissez-la sur
null
)2: appeler
GC.Collect()
3: Excel doit être fermé, soit par l'utilisateur fermant manuellement le programme, soit par l'appel
Quit
de l'objet Excel. (Notez queQuit
cela fonctionnera comme si l'utilisateur tentait de fermer le programme et présentera une boîte de dialogue de confirmation s'il y a des modifications non enregistrées, même si Excel n'est pas visible. L'utilisateur peut appuyer sur Annuler, puis Excel n'aura pas été fermé. )1 doit se produire avant 2, mais 3 peut survenir à tout moment.
Une façon de l'implémenter est d'envelopper l'objet Excel d'interopérabilité avec votre propre classe, de créer l'instance d'interopérabilité dans le constructeur et d'implémenter IDisposable avec Dispose ressemblant à quelque chose comme
Cela nettoiera excellent du côté des choses de votre programme. Une fois Excel fermé (manuellement par l'utilisateur ou par vous appelant
Quit
), le processus disparaîtra. Si le programme a déjà été fermé, le processus disparaîtra lors de l'GC.Collect()
appel.(Je ne sais pas à quel point c'est important, mais vous voudrez peut-être un
GC.WaitForPendingFinalizers()
appel après l'GC.Collect()
appel, mais il n'est pas strictement nécessaire de se débarrasser du processus Excel.)Cela a fonctionné pour moi sans problème pendant des années. Gardez à l'esprit cependant que pendant que cela fonctionne, vous devez en fait fermer correctement pour que cela fonctionne. Vous obtiendrez toujours des processus excel.exe accumulés si vous interrompez votre programme avant le nettoyage d'Excel (généralement en appuyant sur "stop" pendant le débogage de votre programme).
la source
Marshal
.Pour ajouter aux raisons pour lesquelles Excel ne se ferme pas, même lorsque vous créez des références directes à chaque objet lors de la lecture, la création est la boucle `` Pour ''.
la source
J'ai traditionnellement suivi les conseils trouvés dans la réponse de VVS . Cependant, dans un effort pour garder cette réponse à jour avec les dernières options, je pense que tous mes futurs projets utiliseront la bibliothèque "NetOffice".
NetOffice est un remplacement complet des PIA Office et est totalement indépendant de la version. Il s'agit d'une collection d'encapsuleurs COM gérés qui peuvent gérer le nettoyage qui provoque souvent de tels maux de tête lorsque vous travaillez avec Microsoft Office dans .NET.
Certaines fonctionnalités clés sont:
Je ne suis en aucun cas affilié au projet; J'apprécie vraiment sincèrement la nette réduction des maux de tête.
la source
La réponse acceptée ici est correcte, mais notez également que non seulement les références "à deux points" doivent être évitées, mais également les objets qui sont récupérés via l'index. Vous n'avez pas non plus besoin d'attendre que vous ayez terminé avec le programme pour nettoyer ces objets, il est préférable de créer des fonctions qui les nettoieront dès que vous en aurez terminé, lorsque cela sera possible. Voici une fonction que j'ai créée qui attribue certaines propriétés d'un objet Style appelé
xlStyleHeader
:Notez que je devais définir
xlBorders[Excel.XlBordersIndex.xlEdgeBottom]
une variable pour nettoyer cela (pas à cause des deux points, qui font référence à une énumération qui n'a pas besoin d'être publiée, mais parce que l'objet auquel je fais référence est en fait un objet Border qui doit être libéré).Ce genre de chose n'est pas vraiment nécessaire dans les applications standard, qui font un excellent travail de nettoyage après elles-mêmes, mais dans les applications ASP.NET, si vous en manquez même une, quelle que soit la fréquence à laquelle vous appelez le garbage collector, Excel toujours en cours d'exécution sur votre serveur.
Cela nécessite beaucoup d'attention aux détails et de nombreuses exécutions de test lors de la surveillance du Gestionnaire des tâches lors de l'écriture de ce code, mais cela vous évite d'avoir à chercher désespérément dans les pages de code pour trouver l'instance que vous avez manquée. Ceci est particulièrement important lorsque vous travaillez dans des boucles, où vous devez libérer CHAQUE INSTANCE d'un objet, même s'il utilise le même nom de variable à chaque fois qu'il boucle.
la source
Après avoir essayé
GC.Collect()
etGC.WaitForPendingFinalizers()
deux fois à la finla solution finale qui fonctionne pour moi est de déplacer un ensemble de
que nous avons ajouté à la fin de la fonction dans un wrapper, comme suit:
la source
J'ai suivi cela exactement ... Mais j'ai quand même rencontré des problèmes 1 fois sur 1000. Qui sait pourquoi. Il est temps de sortir le marteau ...
Juste après l'instanciation de la classe d'application Excel, je saisis le processus Excel qui vient d'être créé.
Ensuite, une fois que j'ai effectué tout le nettoyage COM ci-dessus, je m'assure que ce processus n'est pas en cours d'exécution. S'il est toujours en cours d'exécution, tuez-le!
la source
¨ ° º¤ø „¸ Tirez sur Excel proc et mâchez du chewing-gum ¸„ ø¤º ° ¨
la source
Vous devez être conscient qu'Excel est également très sensible à la culture sous laquelle vous travaillez.
Vous pouvez constater que vous devez définir la culture sur EN-US avant d'appeler les fonctions Excel. Cela ne s'applique pas à toutes les fonctions - mais à certaines d'entre elles.
Cela s'applique même si vous utilisez VSTO.
Pour plus de détails: http://support.microsoft.com/default.aspx?scid=kb;en-us;Q320369
la source
«Ne jamais utiliser deux points avec des objets COM» est une bonne règle pour éviter les fuites de références COM, mais Excel PIA peut entraîner des fuites de plus de façons qu’apparentes à première vue.
L'une de ces méthodes consiste à s'abonner à tout événement exposé par l'un des objets COM du modèle d'objet Excel.
Par exemple, s'abonner à l'événement WorkbookOpen de la classe Application.
Un peu de théorie sur les événements COM
Les classes COM exposent un groupe d'événements via des interfaces de rappel. Afin de souscrire à des événements, le code client peut simplement enregistrer un objet implémentant l'interface de rappel et la classe COM invoquera ses méthodes en réponse à des événements spécifiques. Étant donné que l'interface de rappel est une interface COM, il est du devoir de l'objet d'implémentation de décrémenter le nombre de références de tout objet COM qu'il reçoit (en tant que paramètre) pour l'un des gestionnaires d'événements.
Comment Excel PIA expose les événements COM
Excel PIA expose les événements COM de la classe Application Excel en tant qu'événements .NET conventionnels. Chaque fois que le code client s'abonne à un événement .NET (accent sur 'a'), PIA crée une instance d'une classe implémentant l'interface de rappel et l'enregistre auprès d'Excel.
Par conséquent, un certain nombre d'objets de rappel sont enregistrés auprès d'Excel en réponse à différentes demandes d'abonnement à partir du code .NET. Un objet de rappel par abonnement à un événement.
Une interface de rappel pour la gestion des événements signifie que PIA doit s'abonner à tous les événements d'interface pour chaque demande d'abonnement aux événements .NET. Il ne peut pas choisir. Lors de la réception d'un rappel d'événement, l'objet de rappel vérifie si le gestionnaire d'événements .NET associé est intéressé par l'événement en cours ou non, puis appelle le gestionnaire ou ignore silencieusement le rappel.
Effet sur le nombre de références d'instance COM
Tous ces objets de rappel ne décrémentent pas le nombre de références des objets COM qu'ils reçoivent (en tant que paramètres) pour l'une des méthodes de rappel (même pour celles qui sont silencieusement ignorées). Ils s'appuient uniquement sur le garbage collector CLR pour libérer les objets COM.
Étant donné que l'exécution du GC n'est pas déterministe, cela peut entraîner la suspension du processus Excel pendant une durée plus longue que souhaitée et créer une impression de «fuite de mémoire».
Solution
La seule solution pour l'instant consiste à éviter le fournisseur d'événements PIA pour la classe COM et à écrire votre propre fournisseur d'événements qui libère de manière déterministe des objets COM.
Pour la classe Application, cela peut être fait en implémentant l'interface AppEvents puis en enregistrant l'implémentation avec Excel à l'aide de l' interface IConnectionPointContainer . La classe Application (et d'ailleurs tous les objets COM exposant des événements à l'aide du mécanisme de rappel) implémente l'interface IConnectionPointContainer.
la source
Comme d'autres l'ont souligné, vous devez créer une référence explicite pour chaque objet Excel que vous utilisez et appeler Marshal.ReleaseComObject sur cette référence, comme décrit dans cet article de la base de connaissances . Vous devez également utiliser try / finally pour vous assurer que ReleaseComObject est toujours appelé, même lorsqu'une exception est levée. C'est-à-dire au lieu de:
vous devez faire quelque chose comme:
Vous devez également appeler Application.Quit avant de libérer l'objet Application si vous souhaitez qu'Excel se ferme.
Comme vous pouvez le voir, cela devient rapidement extrêmement compliqué dès que vous essayez de faire quoi que ce soit, même modérément complexe. J'ai développé avec succès des applications .NET avec une classe wrapper simple qui encapsule quelques manipulations simples du modèle d'objet Excel (ouvrir un classeur, écrire dans une plage, enregistrer / fermer le classeur, etc.). La classe wrapper implémente IDisposable, implémente soigneusement Marshal.ReleaseComObject sur chaque objet qu'elle utilise et n'expose publiquement aucun objet Excel au reste de l'application.
Mais cette approche ne s'adapte pas bien aux exigences plus complexes.
Il s'agit d'une grande déficience de .NET COM Interop. Pour des scénarios plus complexes, j'envisagerais sérieusement d'écrire une DLL ActiveX en VB6 ou dans un autre langage non géré auquel vous pouvez déléguer toutes les interactions avec des objets COM sortants tels qu'Office. Vous pouvez ensuite référencer cette DLL ActiveX à partir de votre application .NET, et les choses seront beaucoup plus faciles car vous n'aurez qu'à publier cette seule référence.
la source
Lorsque toutes les choses ci-dessus n'ont pas fonctionné, essayez de laisser à Excel le temps de fermer ses feuilles:
la source
Assurez-vous de libérer tous les objets liés à Excel!
J'ai passé quelques heures en essayant plusieurs façons. Ce sont toutes de bonnes idées mais j'ai finalement trouvé mon erreur: si vous ne libérez pas tous les objets, aucune des façons ci-dessus ne peut vous aider comme dans mon cas. Assurez-vous de libérer tous les objets, y compris la première plage!
Les options sont réunies ici .
la source
Un excellent article sur la libération d'objets COM est 2.5 Releasing COM Objects (MSDN).
La méthode que je préconiserais est d'annuler vos références Excel.Interop si ce sont des variables non locales, puis d'appeler
GC.Collect()
etGC.WaitForPendingFinalizers()
deux fois. Les variables Interop étendues localement seront prises en charge automatiquement.Cela supprime la nécessité de conserver une référence nommée pour chaque objet COM.
Voici un exemple tiré de l'article:
Ces mots sont directement tirés de l'article:
la source
La règle des deux points n'a pas fonctionné pour moi. Dans mon cas, j'ai créé une méthode pour nettoyer mes ressources comme suit:
la source
Ma solution
la source
Vous devez être très prudent lorsque vous utilisez des applications d'interopérabilité Word / Excel. Après avoir essayé toutes les solutions, nous avions encore beaucoup de processus "WinWord" ouverts sur le serveur (avec plus de 2000 utilisateurs).
Après avoir travaillé sur le problème pendant des heures, je me suis rendu compte que si
Word.ApplicationClass.Document.Open()
j'ouvrais plus de quelques documents en utilisant simultanément différents threads, le processus de travail IIS (w3wp.exe) plantait, laissant tous les processus WinWord ouverts!Je suppose donc qu'il n'y a pas de solution absolue à ce problème, mais le passage à d'autres méthodes telles que le développement d' Office Open XML .
la source
La réponse acceptée n'a pas fonctionné pour moi. Le code suivant dans le destructeur a fait le travail.
la source
Je travaille actuellement sur la bureautique et suis tombé sur une solution pour cela qui fonctionne à chaque fois pour moi. C'est simple et n'implique pas de tuer aucun processus.
Il semble qu'en parcourant simplement les processus actifs actuels et en "accédant" de quelque manière à un processus Excel ouvert, toute instance suspendue errante d'Excel sera supprimée. Le code ci-dessous vérifie simplement les processus dont le nom est «Excel», puis écrit la propriété MainWindowTitle du processus dans une chaîne. Cette «interaction» avec le processus semble amener Windows à rattraper son retard et à abandonner l'instance figée d'Excel.
J'exécute la méthode ci-dessous juste avant le complément que je développe, se termine, car il déclenche l'événement de déchargement. Il supprime toutes les instances suspendues d'Excel à chaque fois. En toute honnêteté, je ne sais pas vraiment pourquoi cela fonctionne, mais cela fonctionne bien pour moi et pourrait être placé à la fin de toute application Excel sans avoir à se soucier des points doubles, de Marshal.ReleaseComObject, ni des processus de mise à mort. Je serais très intéressé par toute suggestion quant à la raison pour laquelle cela est efficace.
la source
Je pense que c'est en partie la façon dont le cadre gère les applications Office, mais je peux me tromper. Certains jours, certaines applications nettoient immédiatement les processus et d'autres jours, il semble attendre la fermeture de l'application. En général, j'arrête de prêter attention aux détails et je m'assure simplement qu'aucun processus supplémentaire ne flotte à la fin de la journée.
Aussi, et peut-être que je simplifie trop les choses, mais je pense que vous pouvez simplement ...
Comme je l'ai dit plus tôt, je n'ai pas tendance à faire attention aux détails du moment où le processus Excel apparaît ou disparaît, mais cela fonctionne généralement pour moi. Je n'aime pas non plus garder les processus Excel pour autre chose que le minimum de temps, mais je suis probablement juste paranoïaque à ce sujet.
la source
Comme certains l'ont probablement déjà écrit, il n'est pas seulement important de savoir comment fermer Excel (objet); il est également important de savoir comment l' ouvrir et également en fonction du type de projet.
Dans une application WPF, fondamentalement, le même code fonctionne sans ou avec très peu de problèmes.
J'ai un projet dans lequel le même fichier Excel est traité plusieurs fois pour différentes valeurs de paramètres - par exemple, en l'analysant en fonction des valeurs à l'intérieur d'une liste générique.
J'ai mis toutes les fonctions liées à Excel dans la classe de base et l'analyseur dans une sous-classe (différents analyseurs utilisent des fonctions Excel communes). Je ne voulais pas qu'Excel soit ouvert et fermé à nouveau pour chaque élément d'une liste générique, donc je ne l'ai ouvert qu'une seule fois dans la classe de base et je l'ai fermé dans la sous-classe. J'ai eu des problèmes lors du déplacement du code dans une application de bureau. J'ai essayé plusieurs des solutions mentionnées ci-dessus.
GC.Collect()
a déjà été mis en œuvre auparavant, deux fois comme suggéré.J'ai ensuite décidé de déplacer le code pour ouvrir Excel dans une sous-classe. Au lieu d'ouvrir une seule fois, maintenant je crée un nouvel objet (classe de base) et ouvre Excel pour chaque élément et le ferme à la fin. Il y a une certaine perte de performances, mais sur la base de plusieurs tests, les processus Excel se ferment sans problème (en mode débogage), donc les fichiers temporaires sont également supprimés. Je continuerai les tests et j'écrirai plus si j'obtiens des mises à jour.
L'essentiel est: Vous devez également vérifier le code d'initialisation, surtout si vous avez plusieurs classes, etc.
la source