J'ai un service Windows qui ouvre une feuille de calcul Excel via l'objet Microsoft.Office.interop.excel.application. Je voudrais tuer le processus Excel.exe qui est laissé en cours d'exécution après avoir fait fonctionner avec le classeur. P> J'ai essayé ce qui suit sans succès ... p> Quelqu'un a des idées Comment je peux le faire via un service Windows? p> p>
13 Réponses :
J'utiliserais processus.getprocess et rechercher l'exe là-bas Je ne ferais rien faire de quoi que ce soit avec la fenêtre du monde du service, car je pense que les fenêtres sont créées sur un bureau que vous n'avez pas accès. p>
Merci pour votre réponse. Je suis capable de le tuer via une boucle foreach avec process.getProcessbyName ("Excel") mais ce service Windows est multithread, donc je dois tuer le bon exemple.
Je ne sais pas si ma réponse n'est pas ce que vous cherchez ... Si c'est le cas, dis-moi et je vais le supprimer. Quoi qu'il en soit, j'ai utilisé ceci: classeur de fermeture et qui quitte XLAPP supprime Excel.exe de la mémoire dans mon PC. J'ai également essayé d'ouvrir un autre fichier Excel avant de travailler avec cette application de test: une seconde Excel.exe s'ouvre et (à l'aide de cesser) À la fin, laissant la première instance intacte. p> p>
J'utilise Windows XP 32bit 32bit et Microsoft Office 2007. P>
C'est généralement une bonne idée de définir également application.displayalerts = false code> pour empêcher (la plupart) les boîtes de dialogue de blocage d'apparaissant.
J'ai donné cela un essai et ça n'a pas tué l'instance Excel. Le service est en cours d'exécution sur Windows Server 2008 avec Office 2010.
@ Thiag0: J'ai vu que Excel.exe était souvent fermé non pas juste après avoir quitté, mais après avoir quitté la méthode, j'ai appelé Quit () in. Juste pour être sûr que j'ai utilisé gc.collect () aussi, mais cela pourrait aussi être cher ...
fermeture correctement le classeur Open Excel et quitter l'application est extrêmement difficile. Si je peux trouver les liens, je les posterai, mais vous devez essentiellement Nettoyer toutes les références à tout objet COM que vous créez em>. Cela inclut tout de ODBCConnections (connexions de données), de forces de travail, de classeurs et de l'application Excel. Une combinaison je dois travailler impliquée la collecte des ordures et le Comme vous avez mentionné, en boucle et tuez chaque processus Excel est D'habitude pas une bonne idée, car si vous exécutez cela comme une application Windows, vous pouvez fermer Excel sur votre utilisateur, ou dans un service, fermez également une instance d'Excel qui fonctionne via un autre programme. P> Edit: Voir Cette question pour plus d'informations . p> p> system.runtime.interopservices.marshal code> objet:
Merci de me pointer dans la bonne direction. J'ai utilisé votre code avec quelques autres astuces de ce poste et le processus Excel se termine maintenant correctement.
Après beaucoup de lecture et de frustration, j'ai trouvé une solution!
Tous les crédits vont à Dotnetkow , NightCoder et Mike Rosenblum pour leurs solutions sur ce message: Comment nettoyer correctement Excel Interop Objects? P>
Voici ce que j'ai fait ...
de
1. Modification du mode de construction du projet sur "Release" (en mode de débogage, les objets COM ont un temps difficile à éliminer leurs références.
de
2. Supprimé toutes les expressions doubles DOT (tous les objets COM devraient être liés à une variable afin de pouvoir être libérés)
de
3. Appelant GC.Collect (), GC.WAITFORPENDENDINAINALISERS () et Marshal.FinalRelEsEssecomObject () Explicitement dans un blocage enfin P>
Voici le code acutal que j'utilise: P>
Application xlApp = null; Workbooks workbooks = null; Workbook workbook = null; Worksheet sheet = null; Range r = null; object obj = null; try { xlApp = new Application(); xlApp.DisplayAlerts = false; xlApp.AskToUpdateLinks = false; workbooks = xlApp.Workbooks; workbook = workbooks.Open(fileName, 2, false); sheet = workbook.Worksheets[1]; r = sheet.get_Range("F19"); obj = r.get_Value(XlRangeValueDataType.xlRangeValueDefault); } finally { GC.Collect(); GC.WaitForPendingFinalizers(); if (value != null) Marshal.FinalReleaseComObject(value); if (r != null) Marshal.FinalReleaseComObject(r); if (sheet != null) Marshal.FinalReleaseComObject(sheet); if (workbooks != null) Marshal.FinalReleaseComObject(workbooks); if (workbook != null) { workbook.Close(Type.Missing, Type.Missing, Type.Missing); Marshal.FinalReleaseComObject(workbook); } if (xlApp != null) { xlApp.Quit(); Marshal.FinalReleaseComObject(xlApp); } }
J'ai utilisé une solution simple mais efficace trouver tous les processus Excell.exe. Ensuite, obtenez l'ID de processus de mon ExcelApplication. Tuez seulement le processus dont l'identifiant correspond.
Utilisez pour déclarer GetWindowThreadProcessid dans la classe: P> [DllImport("user32.dll")]
private static extern uint GetWindowThreadProcessId(IntPtr hWnd, out uint lpdwProcessId);
Avez-vous lu la réponse acceptée? Votre solution peut fermer Excel sur l'utilisateur que nous ne sommes pas bons. La solution acceptée fonctionne également et évite ce problème. Comment pensez-vous que cette réponse contribue?
@vidstige pour moi personnellement cette réponse a contribué la seule solution qui a fonctionné. J'ai une application extrêmement basique qui automatise Access 2000 sur Windows Server 2008R2 64bit. Je me suis assuré que je suis tout possible d'autres directives recommandées, mais mes processus ne se ferment pas. En utilisant cette approche, je peux utiliser le PID pour continuer à fermer les instances que j'ai besoin.
@Safrin, j'aimerais pouvoir vous donner plus de +1. Merci beaucoup d'avoir pris le temps. :) J'allais absolument noix avec cette atmosphère.
La solution est fausse. Le processus Excel restera en vie jusqu'à ce que l'appelant marshal.finalRelReeeSecomObject (XLAPP); code>. Pour cette raison, vous le tuez toujours par la force b> même avant que cela soit libéré gracieusement. Je suggère de modifier votre réponse et de changer les lignes du code. De plus, de ma propre expérience, bien que vous libérez tout ce que vous devez, le code de macro que vous rencontrez par Interop pourrait laisser quelque chose derrière et cela bloquera votre application de la sortie. Il est bon d'avoir ce système de sauvegarde si vous pouvez l'appliquer à votre utilisation spécifique d'Excel (avoir à l'esprit les autres utilisateurs Excel).
ci-dessous est le code qui ouvre et supprime l'instance Excel. Nous devons juste vous assurer que tous les objets liés à Excel sont fermés.
Vous devez vérifier les poignées de fichier et obtenir PID, qui sont ouvertes par processus, puis la tuez-la. Cela a fonctionné pour moi.
Votre réponse mérite le poids en or !!! J'ai essayé de travailler cela pendant des mois !!!
Ma solution
[DllImport("user32.dll")] static extern int GetWindowThreadProcessId(int hWnd, out int lpdwProcessId); private void GenerateExcel() { var excel = new Microsoft.Office.Interop.Excel.Application(); int id; // Find the Process Id GetWindowThreadProcessId(excel.Hwnd, out id); Process excelProcess = Process.GetProcessById(id); try { // Your code } finally { excel.Quit(); // Kill him ! excelProcess.Kill(); }
"user32.dll" son nom de DLL si oui alors de l'endroit où je reçois cela?
J'utilise:
Process[] AllProcesses = Process.GetProcessesByName("EXCEL.EXE");
Peut-être que ce n'est pas si élégant, mais j'ai fini par une combinaison de la solution acceptée et celle de Safrin. Donc, j'essaie d'abord de le faire de manière élégante et si elle échoue, j'utilise une force brute. La raison en est que le code fait partie d'une procédure de lot qui doit pouvoir continuer même lorsque une opération d'actualisation de l'excellence d'excellence échoue. Mon problème était que certains échecs ont dû faire de défauts dans le modèle PowerPivot, ce qui a soulevé une boîte de dialogue avec un message d'erreur. Cette boîte de dialogue n'était pas visible car elle fonctionne comme processus d'arrière-plan et il semblait que Excel ne fermerait pas, et mon processus ne se poursuivrait pas, jusqu'à ce que le dialogue soit fermé (?!). Donc, démarrez les procédés dans un fil séparé avec un mécanisme Time Out et tuez Excel sur une élimination de mon objet de travail si la question ne fonctionne pas était la seule solution que je pouvais penser (qui fonctionne) ...
public void Dispose() { GC.Collect(); GC.WaitForPendingFinalizers(); if (workbook != null) { try { workbook.Close(false); Marshal.FinalReleaseComObject(workbook); } catch { } } if (excel != null) { try { excel.Quit(); } catch { int hWnd = excel.Application.Hwnd; uint processID; GetWindowThreadProcessId((IntPtr)hWnd, out processID); Process[] procs = Process.GetProcessesByName("EXCEL"); foreach (Process p in procs) { if (p.Id == processID) p.Kill(); } } Marshal.FinalReleaseComObject(excel); } }
Ceci est mon code pour tuer tous les processus Excel non utilisés
Process[] process = Process.GetProcessesByName("excel"); foreach (Process excel in process) { if (excel.HasExited) { excel.Kill(); } } process = null;
C'est ce que je fais .. sur tuer peut-être .. mais fonctionne bien pour moi.
Pour tuer le processus Excel Exact utilisé pour votre application à ce moment-là, identifiez tout d'abord son PID en entrant dans le code ci-dessous sous les instructions de sauvegarde et de fermeture de votre méthode 1 (méthode potentiellement principale): public CopyPaste2()
{
srcWb= @"C:\WIP\sourceWB.xlsm";
destWb= @"C:\WIP\destinationWB.xlsm";
Application xlApp = new Application();
xlApp.Visible = true;
Workbook strSrcWb= xlApp.Workbooks.Open(srcWb, 0, false, 5, "", "", true, XlPlatform.xlWindows, "\t", false, false, 0, true, 1, 0);
Workbook strDestWb= xlApp.Workbooks.Open(destWb, 0, false, 5, "", "", true, XlPlatform.xlWindows, "\t", false, false, 0, true, 1, 0);
Worksheet srcWs = strSrcWb.Worksheets.get_Item("Sheet1");
Worksheet destWs = strDestWb.Worksheets.get_Item("Sheet1");
... rest of the executive methods ...
strDestWb.Save();
strSrcWb.Close();
strDestWb.Close();
xlApp.Quit();
int pid = -1;
HandleRef hwnd = new HandleRef(xlApp, (IntPtr)xlApp.Hwnd);
GetWindowThreadProcessId(hwnd, out pid);
KillProcess(pid, "EXCEL");
}
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern int GetWindowThreadProcessId(HandleRef handle, out int processId);
static public void KillProcess(int pid, string processName)
{
// to kill current process of excel
Process[] AllProcesses = Process.GetProcessesByName(processName);
foreach (Process process in AllProcesses)
{
if (process.Id == pid)
{
process.Kill();
}
}
AllProcesses = null;
}
J'ai examiné cela sur un site interne et abandonné pour cette raison.