it-roy-ru.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);

Зачем? Что мне не хватает?

11
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 после его использования. Затем установите переменную Nothing в Visual Basic (null в C #), чтобы освободить ссылку на объект.

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