web-dev-qa-db-ja.com

Microsoft.Office.Interop.Excel.Application.Quit()がバックグラウンドプロセスを実行したままにしているのはなぜですか?

次のコードは、プログラムが終了するまで、Microsoft Excelバックグラウンドプロセスを実行したままにします。

var excelApplication = new Application();
var workbooks = excelApplication.Workbooks;
var workbook = excelApplication.Workbooks.Open(file.FullName);

workbook.Close();
excelApplication.Workbooks.Close();
excelApplication.Quit();

Marshal.ReleaseComObject(workbook);
Marshal.ReleaseComObject(workbooks);
Marshal.ReleaseComObject(excelApplication);

どうして?何が欠けていますか?

15
skinnysoftware

とった!

application.Workbooks!= application.Workbooks

このプロパティは変数を公開せず、値を生成します。したがって、Workbooksプロパティにアクセスするたびに、新しいCOMオブジェクトを作成します。

私はコードを修正し、すべてが順調です。ありがとう、みんな。

var excelApplication = new Application();
var workbooks = excelApplication.Workbooks;
var workbook = workbooks.Open(pathToExcelWorkbook); // Fixed

workbook.Close();
workbooks.Close();
excelApplication.Quit();

Marshal.ReleaseComObject(workbook);
Marshal.ReleaseComObject(workbooks);
Marshal.ReleaseComObject(excelApplication);
24
skinnysoftware

これは、Officeアプリケーションで広く発生している問題です。すべてのExcelアドイン/オートメーションアプリケーションは、不要になったときにExcelオブジェクトへの参照を体系的に解放する必要があります。 Excelオブジェクトへの参照を体系的に解放しないと、Microsoft Office Excelが正常にシャットダウンしない場合があります。詳細は 体系的にオブジェクトを解放する を参照してください。 Outlookに関連していますが、同じ原則をすべてのOfficeアプリケーションに適用できます。

System.Runtime.InteropServices.Marshal.ReleaseComObjectを使用して、Excelオブジェクトの使用が終了したら解放します。次に、Visual Basicで変数をNothing(C#ではnull)に設定して、オブジェクトへの参照を解放します。

6
Eugene Astafiev

これはISこれを行うには間違った方法ですしかし、これは問題を修正する最も簡単な方法

    [DllImport("user32.dll")]
    private static extern uint GetWindowThreadProcessId(IntPtr hWnd, out uint lpdwProcessId);

    private Application _excelApp;
    private Workbook _excelWorkBook;
    private Worksheet _excelSheet;

    private void CloseExcelApp()
    {
        int hWnd = _excelApp.Application.Hwnd;
        uint processID;

        GetWindowThreadProcessId((IntPtr)hWnd, out processID);
        Process.GetProcessById((int)processID).Kill();

        _excelWorkBook = null;
        _excelApp = null;
        _excelSheet = null;
    }

必要なのは、初期化されていない変数をすべて操作する必要があるときに初期化し、アプリを閉じる必要があるときにCloseExcelApp()を呼び出すことです。

2
Andrew