Architect's Log

I'm a Cloud Architect. I'm highly motivated to reduce toils with driving DevOps.

複数のCOMオブジェクトを確実に解放する

.NETでCOMを扱う際に、複数のCOMオブジェクトを確実に解放する方法を紹介します。

どういうこと?

.NETではCOMを注意深く扱う必要があります。1オブジェクトでも解放漏れがあるとCOMのプロセスが解放されずに残ってしまうからです。

どうすれば?

ソースコードを記載します。

COM解放メソッドを実装したクラス
using System;
using System.Runtime.InteropServices;

namespace Com {
    /// <summary>
    /// COMオブジェクトを解放する機能を提供します。
    /// </summary>
    public static class ComRelease {
        /// <summary>
        /// 複数のCOMオブジェクトの参照カウントを0までデクリメントし、解放します。
        /// </summary>
        /// <param name="objects">解放するCOMオブジェクトの配列。</param>
        /// <remarks>解放は配列の要素順に行います。</remarks>
        public static void FinalReleaseComObjects(params object[] objects) {
            foreach (object o in objects) {
                try {
                    if (o == null)
                        continue;
                    if (Marshal.IsComObject(o) == false)
                        continue;
                    Marshal.FinalReleaseComObject(o);
                } catch (Exception) {
                }
            }
        }
    }
}
使い方

こんな風に使います。

using System;
using Microsoft.Office.Interop.Excel;

namespace ExcelOpen {
    public static class ExcelOpener {
        public static void OpenExcel(string excelFilePathName) {
            Application application = null;
            Workbooks workbooks = null;
            Workbook workbook = null;

            try {
                application = new Application();
                workbooks = application.Workbooks;

                workbook = workbooks.Open(
                    excelFilePathName, Type.Missing, Type.Missing, Type.Missing, Type.Missing
                    , Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing
                    , Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing);

                // workbookに対して処理を行う

            } finally {
                if (workbook != null) {
                    try {
                        workbook.Close(true, Type.Missing, Type.Missing);
                    } catch {
                    }
                }

                if (application != null) {
                    try {
                        application.Quit();
                    } catch {
                    }
                }

                Com.ComRelease.FinalReleaseComObjects(workbook, workbooks, application);
            }
        }
    }
}