我正在尝试使用以下代码关闭名为TestReport.xlsx的excel文件。当只有一个excel进程正在运行但是当我打开多个excel窗口时,它正在工作,MainWindowTitle发生了变化,代码没有杀死所需的excel进程。
Process[] plist = Process.GetProcessesByName("Excel",".");
foreach(Process p in plist)
{
if (p.MainWindowTitle.Contains("TestReport.xlsx") && p.ProcessName == "EXCEL")
{
p.Kill();
}
}
答案 0 :(得分:0)
您在问题中提供的解释不够准确。你必须区分两种情况:
案例1:您有多个Excel流程,每个流程都有一个工作簿。这意味着,例如所有excel工作簿都在自己的托管excel窗口中运行。例如,右键单击excel图标,获取一个空的excel工作簿并将所需的工作簿加载到该过程中即可实现此目的。在这种情况下,您的方法可行,因为每个excel进程都有自己的标题命名工作簿文件名。迭代excel进程时,请求的进程被终止。
案例2,这是更多"正常"使用excel时可能会引用的情况:您有一个托管多个工作簿的excel进程,每个工作簿可能包含多个工作表。在这种情况下,Excel会按照您的描述进行操作并更改其窗口标题(多文档界面)。
在案例2中,当只有一个excel进程存在时,您可以使用COM Interop以下列方式关闭工作簿:
private void button1_Click(object sender, EventArgs e)
{
CloseExcelWorkbook("TestReport.xlsx");
}
//put the following abbreviation to the "using" block: using Excel = Microsoft.Office.Interop.Excel;
internal void CloseExcelWorkbook(string workbookName)
{
try
{
Process[] plist = Process.GetProcessesByName("Excel", ".");
if (plist.Length > 1)
throw new Exception("More than one Excel process running.");
else if (plist.Length == 0)
throw new Exception("No Excel process running.");
Object obj = Marshal.GetActiveObject("Excel.Application");
Excel.Application excelAppl = (Excel.Application)obj;
Excel.Workbooks workbooks = excelAppl.Workbooks;
foreach (Excel.Workbook wkbk in workbooks )
{
if (wkbk.Name == workbookName)
wkbk.Close();
}
//dispose
//workbooks.Close(); //this would close all workbooks
GC.Collect();
GC.WaitForPendingFinalizers();
if (workbooks != null)
System.Runtime.InteropServices.Marshal.FinalReleaseComObject(workbooks);
//excelAppl.Quit(); //would close the excel application
System.Runtime.InteropServices.Marshal.FinalReleaseComObject(excelAppl);
GC.Collect();
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
如果您只运行一个Excel进程,则此方法有效。当存在多个存在时,情况会更复杂,因为您必须访问所有Excel进程。有关该案例的讨论,请参阅here。
要注意的另一点是正确释放excel对象以避免陈旧的excel对象。请参阅there。
如果省略" dispose"活动,可能会发生这种情况,在关闭Excel并继续运行您的应用程序时,Excel进程将静默运行,如任务管理器中的检查所示。