我有一个 Windows 窗体应用程序,它为用户提供了一个打开的对话框来打开电子表格。
该应用程序对该电子表格执行一些任务,例如排序和删除空白行。然后当它完成时,它使用当前日期作为新文件名的一部分执行另存为。
完成后我想做的是删除原始电子表格。
我正在使用 Microsoft.Office.Interop.Excel。
我在 StackOverflow 上找到了代码(如何正确清理 Excel 互操作对象?),该代码显示了如何关闭 Excel,而 nightcoder 在该帖子中的第三个答案甚至显示了一种方法(我正在使用),它将从进程中删除 Excel任务管理器的选项卡。
我认为一旦 Excel 从任务管理器中转储,它就会删除我试图关闭的文件的冰冷触手般的死亡之握,但我错了。
当代码点击 File.Delete(MyFile) 命令时,它仍然说我无法删除这个文件,因为它上面有一个冰冷的触手状死亡之握或类似的东西。
有谁知道我在哪里可以找到足够大的棒球棒让应用程序放开文件。我真的很想删除它。
==================================================== ============
2013 年 7 月 22 日更新
这是我到目前为止的部分代码。
这段代码的作用是允许用户选择一个 Excel 电子表格,打开它,重命名它,然后关闭它。我删除了一些我认为不必要的操纵电子表格的代码。
我希望它在保存重命名的文件后关闭原始文件,打开重命名的文件并退出应用程序,同时将重命名的电子表格打开以进行任何进一步的编辑。
目前它不这样做。它仅使用新名称创建电子表格,然后关闭应用程序和电子表格。然后我必须手动打开新的电子表格。
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.IO;
using System.Runtime.InteropServices;
using Excel = Microsoft.Office.Interop.Excel;
using System.Diagnostics;
using Microsoft.Office.Interop.Excel;
namespace Weekly_Stats_Organizer
{
public partial class Form1 : Form
{
[DllImport("user32.dll")]
private static extern uint GetWindowThreadProcessId(IntPtr hWnd, out uint lpdwProcessId);
string _ExcelFileName;
private string ExcelFileName
{
get { return _ExcelFileName; }
set { _ExcelFileName = value; }
}
private string DefaultPath = "C:\\My Documents\\Weekly Stats";
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
Stream FileName = null;
OpenFileDialog OpenExcelSpreadsheet = new OpenFileDialog();
OpenExcelSpreadsheet.InitialDirectory = DefaultPath;
OpenExcelSpreadsheet.Filter = "Excel 2003 (*.xls)|*.xls|Excel 2007 (*.xlsx)|*.xlsx";
OpenExcelSpreadsheet.FilterIndex = 1;
OpenExcelSpreadsheet.RestoreDirectory = true;
if(OpenExcelSpreadsheet.ShowDialog() == DialogResult.OK)
{
if((FileName = OpenExcelSpreadsheet.OpenFile()) != null)
{
ExcelFileName = ((System.Windows.Forms.FileDialog)(OpenExcelSpreadsheet)).FileName;
GenerateWorkbook();
}
}
}
private void GetExcel()
{
Excel.Application ExcelApp = null;
Excel.Workbook ExcelWorkBook = null;
Excel.Sheets ExcelSheets = null;
Excel.Worksheet MySheet = null;
try
{
DateTime CurrentDate = DateTime.Today;
string FileName = DefaultPath + "\\" + CurrentDate.Year.ToString() + "-" + CurrentDate.Month.ToString("D2") + "-" + CurrentDate.Day.ToString("D2") + " Weekly Stats.xls";
ExcelApp = new Excel.Application();
ExcelApp.Visible = false;
ExcelWorkBook = ExcelApp.Workbooks.Open(ExcelFileName, 0, true, 5, "", "", false, Excel.XlPlatform.xlWindows, "", true, false, 0, true, false, false);
ExcelSheets = ExcelWorkBook.Worksheets;
MySheet = (Excel.Worksheet)ExcelSheets.get_Item("Sheet 1");
ExcelWorkBook.SaveAs(FileName, Excel.XlFileFormat.xlWorkbookNormal, "", "", false, false,
Excel.XlSaveAsAccessMode.xlNoChange, Excel.XlSaveConflictResolution.xlUserResolution, true, "", "", "");
//GC.Collect();
//GC.WaitForPendingFinalizers();
Marshal.ReleaseComObject(MySheet);
Marshal.ReleaseComObject(ExcelSheets);
MySheet = null;
ExcelSheets = null;
ExcelWorkBook.Close(false, System.Reflection.Missing.Value, System.Reflection.Missing.Value);
}
finally
{
Marshal.ReleaseComObject(ExcelWorkBook);
int hWnd = ExcelApp.Application.Hwnd;
TryKillProcessByMainWindowHwnd(hWnd);
Marshal.ReleaseComObject(ExcelApp);
ExcelWorkBook = null;
ExcelApp = null;
//if (File.Exists(ExcelFileName))
// File.Delete(ExcelFileName);
System.Windows.Forms.Application.Exit();
}
}
//=========================================================================================================================================
//=========================================================================================================================================
//=========================================================================================================================================
// This code was found at https://stackoverflow.com/questions/158706/how-to-properly-clean-up-excel-interop-objects
// is the answer provided by nightcoder. This solution seems to be the only one that actually clears the Excel instance out of the
// Processes in Windows Task Manager. The idea is to completely shut down Excel so that I can delete the original spreadsheet. So far not
// working out so well.
private void GenerateWorkbook()
{
try
{
GetExcel();
}
finally
{
GC.Collect();
GC.WaitForPendingFinalizers();
}
}
//=============================================================================================================================================
/// <summary> Tries to find and kill process by hWnd to the main window of the process.</summary>
/// <param name="hWnd">Handle to the main window of the process.</param>
/// <returns>True if process was found and killed. False if process was not found by hWnd or if it could not be killed.</returns>
public static bool TryKillProcessByMainWindowHwnd(int hWnd)
{
uint processID;
GetWindowThreadProcessId((IntPtr)hWnd, out processID);
if (processID == 0) return false;
try
{
Process.GetProcessById((int)processID).Kill();
}
catch (ArgumentException)
{
return false;
}
catch (Win32Exception)
{
return false;
}
catch (NotSupportedException)
{
return false;
}
catch (InvalidOperationException)
{
return false;
}
return true;
}
/// <summary> Finds and kills process by hWnd to the main window of the process.</summary>
/// <param name="hWnd">Handle to the main window of the process.</param>
/// <exception cref="ArgumentException">
/// Thrown when process is not found by the hWnd parameter (the process is not running).
/// The identifier of the process might be expired.
/// </exception>
/// <exception cref="Win32Exception">See Process.Kill() exceptions documentation.</exception>
/// <exception cref="NotSupportedException">See Process.Kill() exceptions documentation.</exception>
/// <exception cref="InvalidOperationException">See Process.Kill() exceptions documentation.</exception>
public static void KillProcessByMainWindowHwnd(int hWnd)
{
uint processID;
GetWindowThreadProcessId((IntPtr)hWnd, out processID);
if (processID == 0)
throw new ArgumentException("Process has not been found by the given main window handle.", "hWnd");
Process.GetProcessById((int)processID).Kill();
}
//=========================================================================================================================================
//=========================================================================================================================================
//=========================================================================================================================================
}
}