我试图通过这种方式将Columns数据从列表中的Excel文件中获取:
private void Form1_Load(object sender, EventArgs e)
{
Excel.Application xlApp = new Excel.Application();
Excel.Workbook xlWorkbook = xlApp.Workbooks.Open(@"D:/test.xlsx");
Excel.Worksheet xlWorksheet = xlWorkbook.Sheets[1];
Excel.Range xlRange = xlWorksheet.UsedRange;
int rowCount = xlRange.Rows.Count;
int colCount = xlRange.Columns.Count;
List<string> FirstColumnValues = new List<string>();
List<string> SecondColumnValues = new List<string>();
for (int row=1; row <= rowCount; row++)
{
for (int col = 1; col <= colCount; col++)
{
switch (col)
{
case 1:
FirstColumnValues.Add(xlRange.Cells[row, col].Value2.ToString());
break;
case 2:
SecondColumnValues.Add(xlRange.Cells[row, col].Value2.ToString());
break;
}
}
}
if (FirstColumnValues.Count != 0 && SecondColumnValues.Count != 0)
{
xlWorkbook.Close();
xlApp.Quit();
MessageBox.Show("Completed");
Marshal.ReleaseComObject(xlRange);
Marshal.ReleaseComObject(xlWorksheet);
Marshal.ReleaseComObject(xlWorkbook);
Marshal.ReleaseComObject(xlApp);
xlApp = null;
}
}
问题是,即使我已经尝试了所有正确关闭它的事情,但进程EXCEL.EXE
仍未关闭。我知道这里有很多关于正确关闭excel过程的问题。但我不是专业人士,我几乎尝试了所有我能做的事情。
仍然没有运气。
那么,任何人都可以告诉我这段代码有什么问题吗?当所有数据都存储在列表中时,如何关闭进程?
答案 0 :(得分:3)
我知道这个问题已经得到了回答,但我想我会分享我试图解决同样问题的方法。希望有人会觉得这很有用。这是在vb.net中,但我确信它可以翻译。
Dim proc As System.Diagnostics.Process
For Each proc In System.Diagnostics.Process.GetProcessesByName("EXCEL")
If proc.MainWindowTitle.ToString = "" Then
proc.Kill()
End If
Next
我发现当我通过我的应用程序打开Excel文件时,窗口标题为空,因此我没有关闭每个正在运行的Excel进程,而是关闭了没有标题的那些。
修改强>
如果你要终止这个过程,因为你找不到left over variables that haven't been cleaned up(基本上你用两个点设置的任何变量),那么至少要杀掉正确的Excel实例:
[DllImport("user32.dll", SetLastError = true)]
private static extern int GetWindowThreadProcessId(IntPtr hwnd, ref int lpdwProcessId);
...
if (xlApp != null)
{
GetWindowThreadProcessId(new IntPtr(xlApp.Hwnd), ref excelProcessId);
Process ExcelProc = Process.GetProcessById(excelProcessId);
if (ExcelProc != null)
{
ExcelProc.Kill();
}
我不主张杀戮过程,你应该用VSTO Contrib正确清理,例如:
using (var xlApp = new Microsoft.Office.Interop.Excel.Application().WithComCleanup())
答案 1 :(得分:1)
我以前去过那里。这篇文章真正帮助我解决了这个问题:
Excel似乎非常顽固地终止了这个过程。您很可能最终会使用System.Diagnostics.Process终止该进程。答案 2 :(得分:1)
也许,您可以考虑使用try{}catch{}finally{}
,然后尝试Marshal.FinalReleaseComObject。
不确定您是否看过this post,也可能会给您一些见解。
答案 3 :(得分:1)
确保运行Excel实例最终终止(即应用程序退出时)的最简单方法是将顶级对象包装在try / finally块中。
Excel.Application xlApp;
try{
xlApp = new Excel.Application();
...do some work...
}
finally{
xlApp.DisableAlerts=True;
xlApp.Quit();
xlApp.DisableAlerts=False;
Marshal.ReleaseComObject(xlApp);
}
//If you don't mind having the Excel process kept alive for a while,
//you don't even have to call ReleaseComObject() on the intermediate objects.
//The runtime will eventually free the underlying COM objects.
//If you want to clean up right away, your bookkeeping needs to be more thorough.
//Every time you access a method or property that returns a runtime callable wrapper
//(System.__ComObject), you'll need to assign them to a variable
//and make sure Marshal.ReleaseComObject() is called.
// More thorough bookkeeping...
Excel.Application xlApp;
try{
xlApp = new Excel.Application();
Excel.Workbooks xlWorkbooks = xlApp.Workbooks;
Excel.Workbook xlWorkbook = xlWorkbooks.Open(@"D:/test.xlsx");
Excel.Sheets xlSheets = xlWorkbook.Sheets;
Excel.Worksheet xlWorksheet = xlSheets[1];
Excel.Range xlRange = xlWorksheet.UsedRange;
...inside the loop...
Excel.Range xlCell = xlRange.Cells[row, col];
FirstColumnValues.Add(xlCell.Value2.ToString());
Marshal.ReleaseComObject(xlCell);
...inside the loop...
Excel.Range xlCell = xlRange.Cells[row, col];
SecondColumnValues.Add(xlCell.Value2.ToString());
Marshal.ReleaseComObject(xlCell);
...do more work...
...clean up...
Marshal.ReleaseComObject(xlRange);
Marshal.ReleaseComObject(xlWorksheet);
Marshal.ReleaseComObject(xlSheets);
Marshal.ReleaseComObject(xlWorkbook);
Marshal.ReleaseComObject(xlWorkbooks);
}
finally{
xlApp.DisableAlerts=True;
xlApp.Quit();
xlApp.DisableAlerts=False;
Marshal.ReleaseComObject(xlApp);
}