2

I have a class which I think makes more sense to make static, as it is basically a utility class. As a part of this class, I am interoping with Microsoft Access and Microsoft Excel.

Obviously, Office Interop objects are unmanaged resources, and a static class cannot have a destructor. I feel that it make sense to only have one instance of an Excel.Application object, and one instance of an Access.Application object that my various methods can make use of, taking care to close my databases and workbooks, and handle errors appropriately.

My issue comes when I close the program, if I don't run System.Runtime.InteropServices.Marshal.ReleaseComObject("myOfficeApplicationInstance");, the Office instances hang around in my task manager. If I release the object while my application is running, then I can't use it again.

I'm not sure if that all made sense so some code is below:

using System;
using Excel = Microsoft.Office.Interop.Excel.Application;
using Access = Microsoft.Office.Interop.Access.Application;

namespace QWERTY
{
    internal static class CreateReport
    {
        private static readonly Excel _excel;
        private static readonly Access _access;

        static CreateReport()
        {
            _excel = new Excel();
            _access = new Access();
        }

        internal static void Performance(DateTime reportDate)
        {
            _excel.Workbooks.Open(@"C:\whatever.xlsx");

            //Do stuff with Excel

            _excel.Workbooks.Close();

            _access.OpenCurrentDatabase(@"C:\whatever.accdb");

            //Do stuff with Access

            _access.CloseCurrentDatabase();
        }
    }
}

A few questions

  1. Am I right that this should be a static class?
  2. How do I deal with unmanaged resources when I am finished using a static class?
JMK
  • 27,273
  • 52
  • 163
  • 280
  • This is a sign of a far more serious problem, something is wrong with the finalizer thread. You can put a band-aid on it with the AppDomain.CurrentDomain.Unload event. – Hans Passant Sep 14 '12 at 13:29
  • @HansPassant Thanks, I am now subscribing to the `AppDomain.CurrentDomain.DomainUnload` and releasing my COM objects in the event handler, but by a `a far more serious problem` are you implying that I shouldn't be using a static class in the first place? – JMK Sep 14 '12 at 13:46
  • No, a static class is not a problem. The finalizer thread not running and releasing the COM objects automatically at the end of the program *is* a problem. – Hans Passant Sep 14 '12 at 13:49
  • Well that gives me something to think about, thankyou! – JMK Sep 14 '12 at 13:55

4 Answers4

2

There are no static finalizers (see here). If you want to make the class static, also add a method to clean up which you call at the end of you application.

An alternative (which I would prefer) is to have a singleton instance, and clean up this instance at the end of your application.

You can also then have a static property to access the instance if you want to. An alternative to the static property is to use some form of DI which you configure to create a single instance. Most DI's offer singleton scopes.

Community
  • 1
  • 1
Maarten
  • 22,527
  • 3
  • 47
  • 68
2

If you wish to go static way implement class that inherits the CriticalFinalizerObject Class. Put your static class cleanup in it's finalizer, then add one instance of that class as a field of your static class. Then if app exits or your app domain unloads that instance finalizer would be run clening up static class.

JMK
  • 27,273
  • 52
  • 163
  • 280
user629926
  • 1,910
  • 2
  • 18
  • 43
1

The best way to deal with unmanaged resources is to wrap them in a class that implements IDisposable. You should then use that class in a using block to ensure proper cleanup. Since all classes that contain IDisposable members should be IDisposable themselves it follows that setting them as a static class members is not a great idea.

You can always release them when your application is exiting, yo do have that event.

Are you sure that you cannot open Excel twice inside your application?

Toni Petrina
  • 7,014
  • 1
  • 25
  • 34
0

Sorry but Office Interop objects are considered as managed resources as Excel and Access don't implement Idisposable interface.

Did you try to close your application properly with Excel.Quit statement? I don't see it in the code you posted.

marco
  • 1