如何关闭Excel com对象并保存工作?

时间:2009-03-26 17:30:19

标签: excel

这让我疯狂。我在这里找到了关于Excel com对象的类似帖子,但是在我的代码完成运行后,我尝试的解决方案都没有成功关闭Excel。 Excel.dll将在TaskManager上停留。

有人可以查看下面的代码,让我知道Excel为什么不关闭?

Try
        'First get an application instance
        xlApp = New Excel.Application()
        'Second open the workbook you need
        xlBook = xlApp.Workbooks.Open(_FileInfo.FullName)
        xlSheet = xlBook.Worksheets(sheetName)
        'set visibility
        xlApp.Visible = False
        Dim row As Integer = 2
        For Each t In upsRecordList
            While (row < upsRecordList.Count + 2)
                xlSheet.Cells(row, 1) = t.StartDate
                xlSheet.Cells(row, 2) = t.AccountTypeCode
                row += 1
            End While
        Next
    Catch ex As Exception
        Throw ex
    Finally
        If Not xlApp Is Nothing Then
            GC.Collect()
            GC.WaitForPendingFinalizers()
            GC.Collect()
            GC.WaitForPendingFinalizers()
            NAR(xlSheet)
            If Not xlBook Is Nothing Then
                xlBook.Close(SaveChanges:=True)
                NAR(xlBook)
            End If
            xlApp.Quit()
            NAR(xlApp)
        End If
    End Try

 Private Sub NAR(ByVal o As Object)
    Try
        Marshal.FinalReleaseComObject(o)
    Catch
    Finally
        o = Nothing
    End Try
End Sub

5 个答案:

答案 0 :(得分:2)

这就是我所做的:

将您的Excel实例保持为单身:

// Our singleton excel instance
private static Excel.Application instance;

/// <summary>
/// Returns an instance of an Excel Application.
/// This instance is a singleton.
/// </summary>
public static Excel.Application GetInstance
{
    get
    {
        if (instance == null)
        {
            try
            {
                instance = new Excel.Application();
                // Give the app a GUID so we can kill it later
                instance.Caption = System.Guid.NewGuid().ToString().ToUpper(CultureInfo.CurrentCulture);
                instance.Visible = false;
            }
            catch (COMException ce)
            {
                ShowMessage(ce.Message, MessageBoxIcon.Error);
            }
        }
        return instance;
    }
}

当你完成后,你可以摧毁它:

   public static void DestroyInstance()
    {
        if (instance != null)
        {
            // Close the workbooks
            object missing = Type.Missing;
            foreach (Excel.Workbook book in GetInstance.Workbooks)
            {
                book.Close(false, book.FullName, missing);
            }

        String appVersion = instance.Version;
        String appCaption = instance.Caption;
        IntPtr appHandle = IntPtr.Zero;
        if (Convert.ToDouble(appVersion, CultureInfo.CurrentCulture) >= 10)
        {
            appHandle = new IntPtr(instance.Parent.Hwnd);
        }

        // Quit and release the object
        instance.Workbooks.Close();
        instance.Quit();
        Release(instance);

        // Force a cleanup.  MSDN documentation shows them making
        // two sets of collect and wait calls.
        System.GC.Collect();
        System.GC.WaitForPendingFinalizers();
        System.GC.Collect();
        System.GC.WaitForPendingFinalizers();

        EnsureProcessKilled(appHandle, appCaption);
    }
}

EnsureProcessKilled方法如下所示:

/// <summary>
/// This method contains a number of ways to try and kill
/// the Excel process created when an instance is instantiated.
/// </summary>
/// <param name="windowHandle">Handle of the application window</param>
/// <param name="caption">A custom GUI stored as the app's caption</param>
public static void EnsureProcessKilled(IntPtr windowHandle, String caption)
{
    NativeMethods.SetLastError(0);
    if (IntPtr.Equals(windowHandle, IntPtr.Zero))
    {
        windowHandle = NativeMethods.FindWindow(null, caption);
    }
    if (IntPtr.Equals(windowHandle, IntPtr.Zero))
    {
        // Can't find the window; assumed it's closed
        return;
    }
    int resourceId;
    int processId = 0;
    resourceId = NativeMethods.GetWindowThreadProcessId(windowHandle, ref processId);
    if (processId == 0)
    {
        // Can't get process id
        if (NativeMethods.EndTask(windowHandle) != 0)
        {
            return; // Success
        }
    }
    // Couldn't end it nicely, let's kill it
    System.Diagnostics.Process process;
    process = System.Diagnostics.Process.GetProcessById(processId);
    process.CloseMainWindow();
    process.Refresh();
    if (process.HasExited)
    {
        return;
    }
    // If we get here, it's being really stubborn.  Say goodbye, EXCEL.EXE!
    process.Kill();
}

你将需要NativeMethods类:

public static class NativeMethods
{

    [DllImport("user32.dll")]
    internal static extern int EndTask(IntPtr windowHandle);

    [DllImport("user32.dll", CharSet = CharSet.Unicode)]
    internal static extern IntPtr FindWindow(String className, String windowName);

    [DllImport("user32.dll")]
    internal static extern int GetWindowThreadProcessId(IntPtr windowHandle, ref int processId);

    [DllImport("kernel32.dll")]
    internal static extern IntPtr SetLastError(int errorCode);

}

另外一个小助手功能:

public static void Release(Object releasable)
{
    System.Runtime.InteropServices.Marshal.ReleaseComObject(releasable);
    releasable = null;
}

答案 1 :(得分:0)

你的代码很好。释放对象时,甚至使用Quit方法,Excel也不会始终完全关闭。

我想你可以遍历正在运行的任务,强制终止它,但我不建议这样做。

答案 2 :(得分:0)

这是我的最后一块; AFAIK这并没有在我们的应用程序中发布Excel。我们让Excel保持打开状态,并依赖用户关闭它。需要为您引用的Excel对象自定义对Marshal.FinalReleaseComObject的调用。

        finally
        {
            GC.Collect();
            GC.WaitForPendingFinalizers();
            GC.Collect();
            GC.WaitForPendingFinalizers();
            // Calls are needed to avoid memory leak
            Marshal.FinalReleaseComObject(sheet);
            Marshal.FinalReleaseComObject(book);
            Marshal.FinalReleaseComObject(excel);
        }

答案 3 :(得分:0)

从Quit语句中删除parens:xlApp.Quit

在该行之后,立即添加:设置xlApp = Nothing

答案 4 :(得分:0)

我再次(现已注册)。另一件事 - 除非您将值传递给变量,否则不要将parens用于Excel参数。代码应为:

   If Not xlApp Is Nothing Then
        GC.Collect()
        GC.WaitForPendingFinalizers()
        GC.Collect()
        GC.WaitForPendingFinalizers()
        NAR(xlSheet)
        If Not xlBook Is Nothing Then
            xlBook.Close True
            xlBook = Nothing
        End If
        xlApp.Quit
        xlApp = Nothing
    End If