Закрытие процесса приложения Excel в C# после доступа к данным
Я пишу приложение на C#, которая открывает файл шаблона Excel для операций чтения/записи. Я хочу, чтобы когда пользователь закрывает приложение, процесс приложения Excel был закрыт без сохранения файла Excel. См. мой Диспетчер задач после нескольких запусков приложения.

Я использую этот код, чтобы открыть файл Excel :
public Excel.Application excelApp = new Excel.Application();
public Excel.Workbook excelBook;
excelBook = excelApp.Workbooks.Add(@"C:/pape.xltx");
и для доступа к данным, я использую этот код :
Excel.Worksheet excelSheet = (Worksheet)(excelBook.Worksheets[1]);
excelSheet.DisplayRightToLeft = true;
Range rng;
rng = excelSheet.get_Range("C2");
rng.Value2 = txtName.Text;
Я вижу подобные вопросы в stackoverflow, такие как этот вопрос и этот, и тестовые ответы, но он не работает.
15 ответов:
попробуйте это:
excelBook.Close(0); excelApp.Quit();при закрытии рабочей книги у вас есть три необязательных параметра:
Workbook.close SaveChanges, filename, routeworkbook
Workbook.Close(false)или если вы делаете позднюю привязку, иногда проще использовать нольWorkbook.Close(0)Вот как я сделал это при автоматизации закрытия книги.также я пошел и посмотрел документацию для него, и нашел его здесь: Книга Excel Закрыть
спасибо,
xlBook.Save(); xlBook.Close(true); xlApp.Quit(); System.Runtime.InteropServices.Marshal.ReleaseComObject(xlApp);попробуйте это.. это сработало для меня... вы должны освободить этот объект приложения xl, чтобы остановить процесс.
подумайте об этом, это убивает процесс:
System.Diagnostics.Process[] process=System.Diagnostics.Process.GetProcessesByName("Excel"); foreach (System.Diagnostics.Process p in process) { if (!string.IsNullOrEmpty(p.ProcessName)) { try { p.Kill(); } catch { } } }кроме того, вы пытались просто закрыть его нормально?
myWorkbook.SaveAs(@"C:/pape.xltx", missing, missing, missing, missing, missing, Microsoft.Office.Interop.Excel.XlSaveAsAccessMode.xlNoChange, missing, missing, missing, missing, missing); excelBook.Close(null, null, null); // close your workbook excelApp.Quit(); // exit excel application excel = null; // set to NULL
Ref:https://stackoverflow.com/a/17367570/132599
избегайте использования выражений с двумя точками, например:
var workbook = excel.Workbooks.Open(/*params*/)...потому что таким образом вы создаете объекты RCW не только для книги, но и для книг, и вы должны освободить его тоже (что невозможно, если ссылка на объект не поддерживается).
это решило проблему для меня. Ваш код становится:
public Excel.Application excelApp = new Excel.Application(); public Excel.Workbooks workbooks; public Excel.Workbook excelBook; workbooks = excelApp.Workbooks; excelBook = workbooks.Add(@"C:/pape.xltx"); ... Excel.Sheets sheets = excelBook.Worksheets; Excel.Worksheet excelSheet = (Worksheet)(sheets[1]); excelSheet.DisplayRightToLeft = true; Range rng; rng = excelSheet.get_Range("C2"); rng.Value2 = txtName.Text;и затем освободите все эти объекты:
System.Runtime.InteropServices.Marshal.ReleaseComObject(rng); System.Runtime.InteropServices.Marshal.ReleaseComObject(excelSheet); System.Runtime.InteropServices.Marshal.ReleaseComObject(sheets); excelBook .Save(); excelBook .Close(true); System.Runtime.InteropServices.Marshal.ReleaseComObject(xlBook); System.Runtime.InteropServices.Marshal.ReleaseComObject(workbooks); excelApp.Quit(); System.Runtime.InteropServices.Marshal.ReleaseComObject(xlApp);я заворачиваю это в
try {} finally {}чтобы убедиться, что все выйдет, даже если что-то пойдет не так (что может пойти не так?), например,public Excel.Application excelApp = null; public Excel.Workbooks workbooks = null; ... try { excelApp = new Excel.Application(); workbooks = excelApp.Workbooks; ... } finally { ... if (workbooks != null) System.Runtime.InteropServices.Marshal.ReleaseComObject(workbooks); excelApp.Quit(); System.Runtime.InteropServices.Marshal.ReleaseComObject(xlApp); }
убить Excel не всегда легко; смотрите эту статью: 50 способов убить Excel
эта статья принимает лучшие советы от Microsoft (MS Knowlege базовая статья) о том, как заставить Excel выйти красиво, но затем также удостоверяется в этом, убивая процесс, если это необходимо. Мне нравится иметь второй парашют.
убедитесь, что вы закрыли все открытые книги, вышли из приложения и освободили объект xlApp. Наконец, проверьте, чтобы увидеть, если процесс все еще жив, и если да, то убейте его.
эта статья также гарантирует, что мы не убиваем все процессы Excel, а только убиваем точный процесс, который был запущен.
см. также получить процесс из дескриптора окна
вот код, который я использую: (работает все время)
Sub UsingExcel() 'declare process; will be used later to attach the Excel process Dim XLProc As Process 'call the sub that will do some work with Excel 'calling Excel in a separate routine will ensure that it is 'out of scope when calling GC.Collect 'this works better especially in debug mode DoOfficeWork(XLProc) 'Do garbage collection to release the COM pointers 'http://support.microsoft.com/kb/317109 GC.Collect() GC.WaitForPendingFinalizers() 'I prefer to have two parachutes when dealing with the Excel process 'this is the last answer if garbage collection were to fail If Not XLProc Is Nothing AndAlso Not XLProc.HasExited Then XLProc.Kill() End If End Sub 'http://msdn.microsoft.com/en-us/library/ms633522%28v=vs.85%29.aspx <System.Runtime.InteropServices.DllImport("user32.dll", SetLastError:=True)> _ Private Shared Function GetWindowThreadProcessId(ByVal hWnd As IntPtr, _ ByRef lpdwProcessId As Integer) As Integer End Function Private Sub ExcelWork(ByRef XLProc As Process) 'start the application using late binding Dim xlApp As Object = CreateObject("Excel.Application") 'or use early binding 'Dim xlApp As Microsoft.Office.Interop.Excel 'get the window handle Dim xlHWND As Integer = xlApp.hwnd 'this will have the process ID after call to GetWindowThreadProcessId Dim ProcIdXL As Integer = 0 'get the process ID GetWindowThreadProcessId(xlHWND, ProcIdXL) 'get the process XLProc = Process.GetProcessById(ProcIdXL) 'do some work with Excel here using xlApp 'be sure to save and close all workbooks when done 'release all objects used (except xlApp) using NAR(x) 'Quit Excel xlApp.quit() 'Release NAR(xlApp) End Sub Private Sub NAR(ByVal o As Object) 'http://support.microsoft.com/kb/317109 Try While (System.Runtime.InteropServices.Marshal.ReleaseComObject(o) > 0) End While Catch Finally o = Nothing End Try End Sub
excelBook.Закрывать(); excelApp.Выход(); добавьте конец кода, этого может быть достаточно. он работает над моим кодом
Я встретил те же проблемы и попробовал много методов, чтобы решить ее, но не работает. Наконец, я нашел свой путь. Некоторые ссылки Введите описание ссылки здесь
надеюсь, что мой код может помочь кому-то в будущем. Я потратил более двух дней, чтобы решить эту проблему. Ниже приведен мой код:
//get current in useing excel Process[] excelProcsOld = Process.GetProcessesByName("EXCEL"); Excel.Application myExcelApp = null; Excel.Workbooks excelWorkbookTemplate = null; Excel.Workbook excelWorkbook = null; try{ //DO sth using myExcelApp , excelWorkbookTemplate, excelWorkbook } catch (Exception ex ){ } finally { //Compare the EXCEL ID and Kill it Process[] excelProcsNew = Process.GetProcessesByName("EXCEL"); foreach (Process procNew in excelProcsNew) { int exist = 0; foreach (Process procOld in excelProcsOld) { if (procNew.Id == procOld.Id) { exist++; } } if (exist == 0) { procNew.Kill(); } } }
вы можете убить процесс своими
COMобъект excel pidдобавить где-то ниже кода импорта dll
[DllImport("user32.dll", SetLastError = true)] private static extern int GetWindowThreadProcessId(IntPtr hwnd, ref int lpdwProcessId);и использовать
if (excelApp != null) { int excelProcessId = -1; GetWindowThreadProcessId(new IntPtr(excelApp.Hwnd), ref excelProcessId); Process ExcelProc = Process.GetProcessById(excelProcessId); if (ExcelProc != null) { ExcelProc.Kill(); } }
wb.Close(); app.Quit(); System.Diagnostics.Process[] process = System.Diagnostics.Process.GetProcessesByName("Excel"); foreach (System.Diagnostics.Process p in process) { if (!string.IsNullOrEmpty(p.ProcessName) && p.StartTime.AddSeconds(+10) > DateTime.Now) { try { p.Kill(); } catch { } } }он закрывает последний 10 сек процесс с именем "Excel"
правильный способ закрыть весь процесс excel
var _excel = new Application(); foreach (Workbook _workbook in _excel.Workbooks) { _workbook.Close(0); } _excel.Quit(); _excel = null; var process = System.Diagnostics.Process.GetProcessesByName("Excel"); foreach (var p in process) { if (!string.IsNullOrEmpty(p.ProcessName)) { try { p.Kill(); } catch { } } }
на основе других решений. Я должен использовать это:
IntPtr xAsIntPtr = new IntPtr(excelObj.Application.Hwnd); excelObj.ActiveWorkbook.Close(); System.Diagnostics.Process[] process = System.Diagnostics.Process.GetProcessesByName("Excel"); foreach (System.Diagnostics.Process p in process) { if (p.MainWindowHandle == xAsIntPtr) { try { p.Kill(); } catch { } } }С помощью" MainWindowHandle", чтобы определить процесс и закрыть его.
excelObj: это мое приложение Interop excel objecto
использовать переменную для каждого объекта Excel и петли
Marshal.ReleaseComObject >0. Без цикла процесс Excel по-прежнему остается активным.public class test{ private dynamic ExcelObject; protected dynamic ExcelBook; protected dynamic ExcelBooks; protected dynamic ExcelSheet; public void LoadExcel(string FileName) { Type t = Type.GetTypeFromProgID("Excel.Application"); if (t == null) throw new Exception("Excel non installato"); ExcelObject = System.Activator.CreateInstance(t); ExcelObject.Visible = false; ExcelObject.DisplayAlerts = false; ExcelObject.AskToUpdateLinks = false; ExcelBooks = ExcelObject.Workbooks; ExcelBook = ExcelBooks.Open(FileName,0,true); System.Runtime.InteropServices.Marshal.GetActiveObject("Excel.Application"); ExcelSheet = ExcelBook.Sheets[1]; } private void ReleaseObj(object obj) { try { int i = 0; while( System.Runtime.InteropServices.Marshal.ReleaseComObject(obj) > 0) { i++; if (i > 1000) break; } obj = null; } catch { obj = null; } finally { GC.Collect(); } } public void ChiudiExcel() { System.Threading.Thread.CurrentThread.CurrentCulture = ci; ReleaseObj(ExcelSheet); try { ExcelBook.Close(); } catch { } try { ExcelBooks.Close(); } catch { } ReleaseObj(ExcelBooks); try { ExcelObject.Quit(); } catch { } ReleaseObj(ExcelObject); } }
мы можем закрыть приложение Excel при преобразовании xls в xlsx с помощью следующего кода. Когда мы выполняем этот вид задачи, то приложение Excel работает в диспетчере задач, мы должны закрыть этот excel, который работает в фоновом режиме. Interop-это Com-компонент, чтобы освободить com-компонент, который мы использовали Marshal.FinalReleaseComObject.
private void button1_Click(object sender, EventArgs e) { Excel03to07("D:\TestExls\TestExcelApp.XLS"); } private void Excel03to07(string fileName) { string svfileName = Path.ChangeExtension(fileName, ".xlsx"); object oMissing = Type.Missing; var app = new Microsoft.Office.Interop.Excel.Application(); var wb = app.Workbooks.Open(fileName, oMissing, oMissing, oMissing, oMissing, oMissing, oMissing, oMissing, oMissing, oMissing, oMissing, oMissing, oMissing, oMissing, oMissing); wb.SaveAs(svfileName, XlFileFormat.xlOpenXMLWorkbook, Type.Missing, Type.Missing, Type.Missing, Type.Missing, XlSaveAsAccessMode.xlNoChange, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing); wb.Close(false, Type.Missing, Type.Missing); app.Quit(); GC.Collect(); Marshal.FinalReleaseComObject(wb); Marshal.FinalReleaseComObject(app); }
большинство методов работает, но процесс excel всегда остается до закрытия приложения.
когда убить excel процесс один раз он не может быть выполнен еще раз в том же потоке - не знаю, почему.
GetWindowThreadProcessId((IntPtr)app.Hwnd, out iProcessId); wb.Close(true,Missing.Value,Missing.Value); app.Quit(); System.Diagnostics.Process[] process = System.Diagnostics.Process.GetProcessesByName("Excel"); foreach (System.Diagnostics.Process p in process) { if (p.Id == iProcessId) { try { p.Kill(); } catch { } } } } [DllImport("user32.dll")] private static extern uint GetWindowThreadProcessId(IntPtr hWnd, out uint lpdwProcessId); uint iProcessId = 0;этот GetWindowThreadProcessId находит правильный идентификатор процесса o excell .... После убивает его.... Наслаждайся Этим!!!
Comments