3

Will be all unmanaged COM objects released in case if I use code like this

var worksheet = new Application().Workbooks.Add().Worksheets.Add();
Marshal.ReleaseComObject(worksheet);

instead of code like this

var excel = new Application();
var workbook = excel.Workbooks.Add();
var worksheet = workbook.Worksheets.Add();
Marshal.ReleaseComObject(excel);
Marshal.ReleaseComObject(workbook);
Marshal.ReleaseComObject(worksheet);

?

If there is some documentation please send a link in answer.

Yarl
  • 728
  • 1
  • 7
  • 26
  • Maybe use FinalReleaseComObject? https://msdn.microsoft.com/en-us/library/system.runtime.interopservices.marshal.finalreleasecomobject(v=vs.110).aspx – EJoshuaS - Stand with Ukraine Nov 14 '16 at 15:52
  • 4
    Neither is good enough. Never write manual memory management code, you'll get it wrong and don't stand a chance to debug it. http://stackoverflow.com/a/25135685/17034. – Hans Passant Nov 14 '16 at 15:59
  • FinalReleaseComObject still releases only references to particular COM object not all references to all COM object. – Yarl Nov 15 '16 at 07:40

1 Answers1

1

Actually, both code samples will leave an Excel process running in the background. You need to call Application.Quit() on the application object, for example. The following works:

private static void DoExcel()
    {
        var application = new Application();
        var workbook = application.Workbooks.Add();
        var worksheet = workbook.Worksheets.Add();

        // Name that this will be saved as
        string name = workbook.FullName + ".xlsx";

        string fullPath = Path.Combine(Directory.GetCurrentDirectory(), name);
        // If a file of the same name exists, delete it so that we won't be prompted if
        // we want to overwrite it when we save
        if (File.Exists(fullPath))
            File.Delete(fullPath);

        // Save the workbook - otherwise we may be prompted as to whether we want to save when we go to quit
        workbook.Save();

        // Quit the application
        application.Quit();

        // Release the references
        Marshal.ReleaseComObject(worksheet);
        Marshal.ReleaseComObject(workbook);
        Marshal.ReleaseComObject(application);

        // Release the .NET reference and run the garbage collector now to make sure the application is closed immediately
        worksheet = null;
        GC.Collect();
        GC.WaitForPendingFinalizers();
    }

A few other good things to remember: I didn't use it here, but there's a Marshal.FinalReleaseComObject method that's very useful in these cases. Also, again I didn't use this in my code sample, but the Marshal.ReleaseComObject method returns the current count, so you could always do the release in a loop if you wanted to make sure the count reached zero:

while (Marshal.ReleaseComObject(comObject) > 0) { }

You can also use this for debugging purposes - e.g.

int count = Marshal.ReleaseComObject(comObject);
Trace.TraceInformation("Current COM object reference count: " + count.ToString());
  • 1
    Actually I do need to keep Excel running until it will be closed by user interaction. – Yarl Nov 15 '16 at 07:36
  • 1
    @Uzivatel828 You mean user interaction with your program? If so, you don't want to release the application object yet then - you'll need to do all of the stuff with Save and Quit when you want to actually close it. – EJoshuaS - Stand with Ukraine Nov 15 '16 at 16:13
  • There is no garancy that program will be still running in time when the Excel will be closed so all references should be released immediately after work. – Yarl Apr 05 '17 at 09:38