C # - Microsoft.Office.Interop.Word.Application.Quit () не действует [дублировать]

Было опубликовано много хороших ответов, но я хотел бы добавить еще один.

Не все числа могут быть представлены с помощью float / double. Например, будет представлено число «0,2» как «0.200000003» в одинарной точности в стандарте по плавающей точке IEEE754.

Модель для хранения действительных чисел под капотом представляет собой число с плавающей запятой в качестве

Хотя вы можете легко ввести 0.2, FLT_RADIX и DBL_RADIX равно 2; не 10 для компьютера с FPU, который использует «Стандарт IEEE для двоичной арифметики с плавающей запятой (ISO / IEEE Std 754-1985)».

. Точно так же трудно точно представлять такие числа. Даже если вы укажете эту переменную явно без какого-либо промежуточного вычисления.

24
задан Marcus Mangelsdorf 1 February 2016 в 13:27
поделиться

9 ответов

Простое правило: избегайте использования выражений с двумя точками, таких как:

var workbook = excel.Workbooks.Open(/*params*/)

... потому что таким образом вы создаете объекты RCW не только для workbook, но для Workbooks, и вы тоже должны его отпустить (что невозможно, если ссылка на объект не поддерживается).

Итак, правильный путь будет:

var workbooks = excel.Workbooks;
var workbook = workbooks.Open(/*params*/)

//business logic here

Marshal.ReleaseComObject(workbook);
Marshal.ReleaseComObject(workbooks);
Marshal.ReleaseComObject(excel);
56
ответ дан CJBS 24 August 2018 в 07:07
поделиться

В вашем коде у вас есть:

excel.Workbooks.Open(...)

excel.Workbooks создает COM-объект. Затем вы вызываете функцию Open из этого COM-объекта. Однако вы не освобождаете COM-объект, когда вы закончили.

Это обычная проблема при работе с COM-объектами. В принципе, в вашем выражении никогда не должно быть более одной точки, потому что вам нужно будет очистить COM-объекты, когда вы закончите.

Тема просто слишком велика, чтобы полностью исследовать ответ, но Я думаю, вы найдете статью Джейка Гиннивана по этому вопросу чрезвычайно полезной: VSTO и COM Interop

Если вы устали от всех вызовов ReleaseComObject, вы можете найти этот вопрос полезным: Как правильно очистить объект взаимодействия Excel в C #, редакция 2012 года

7
ответ дан Community 24 August 2018 в 07:07
поделиться

В случае отчаяния. Не используйте этот подход, если вы не понимаете, что он делает :

foreach (Process proc in System.Diagnostics.Process.GetProcessesByName("EXCEL"))
{
  proc.Kill();
}

Мне пришлось это сделать, потому что, хотя я закрыл каждый объект COM в своем коде, я все еще У него был упрямый процесс Excel.exe. Конечно, это не лучшее решение.

2
ответ дан Denis Molodtsov 24 August 2018 в 07:07
поделиться

Как указано в других ответах, использование двух точек создаст скрытые ссылки, которые нельзя закрыть Marshal.FinalReleaseComObject. Я просто хотел поделиться своим решением, которое устраняет необходимость запоминать Marshal.FinalReleaseComObject - это очень легко пропустить, и боль, чтобы найти виновника.

Я использую общий класс оболочки IDisposable, который можно использовать на любом COM-объекте. Он работает как шарм, и он держит все красивым и чистым. Я могу даже повторно использовать частные поля (например, this.worksheet). Он также автоматически освобождает объект, когда что-то выдает ошибку из-за характера IDisposable (метод Dispose работает как finally).

using Microsoft.Office.Interop.Excel;

public class ExcelService
{
    private _Worksheet worksheet;

    private class ComObject<TType> : IDisposable
    {
        public TType Instance { get; set; }

        public ComObject(TType instance)
        {
            this.Instance = instance;
        }

        public void Dispose()
        {
            System.Runtime.InteropServices.Marshal.FinalReleaseComObject(this.Instance);
        }
    }

    public void CreateExcelFile(string fullFilePath)
    {
        using (var comApplication = new ComObject<Application>(new Application()))
        {
            var excelInstance = comApplication.Instance;
            excelInstance.Visible = false;
            excelInstance.DisplayAlerts = false;

            try
            {
                using (var workbooks = new ComObject<Workbooks>(excelInstance.Workbooks))
                using (var workbook = new ComObject<_Workbook>(workbooks.Instance.Add()))
                using (var comSheets = new ComObject<Sheets>(workbook.Instance.Sheets))
                {
                    using (var comSheet = new ComObject<_Worksheet>(comSheets.Instance["Sheet1"]))
                    {
                        this.worksheet = comSheet.Instance;
                        this.worksheet.Name = "Action";
                        this.worksheet.Visible = XlSheetVisibility.xlSheetHidden;
                    }

                    using (var comSheet = new ComObject<_Worksheet>(comSheets.Instance["Sheet2"]))
                    {
                        this.worksheet = comSheet.Instance;
                        this.worksheet.Name = "Status";
                        this.worksheet.Visible = XlSheetVisibility.xlSheetHidden;
                    }

                    using (var comSheet = new ComObject<_Worksheet>(comSheets.Instance["Sheet3"]))
                    {
                        this.worksheet = comSheet.Instance;
                        this.worksheet.Name = "ItemPrices";
                        this.worksheet.Activate();

                        using (var comRange = new ComObject<Range>(this.worksheet.Range["A4"]))
                        using (var comWindow = new ComObject<Window>(excelInstance.ActiveWindow))
                        {
                            comRange.Instance.Select();
                            comWindow.Instance.FreezePanes = true;
                        }
                    }

                    if (this.fullFilePath != null)
                    {
                        var currentWorkbook = (workbook.Instance as _Workbook);
                        currentWorkbook.SaveAs(this.fullFilePath, XlFileFormat.xlWorkbookNormal);
                        currentWorkbook.Close(false);
                    }
                }
            }
            catch (Exception ex)
            {
                System.Diagnostics.Trace.WriteLine(ex.Message);
                throw;
            }
            finally
            {
                // Close Excel instance
                excelInstance.Quit();
            }
        }
    }
}
1
ответ дан Heliac 24 August 2018 в 07:07
поделиться

В качестве альтернативы вы можете убить процесс Excel, как описано здесь здесь .

Сначала импортируйте функцию SendMessage:

[DllImport("user32.dll", CharSet = CharSet.Auto)]
private static extern IntPtr SendMessage(IntPtr hWnd, int msg, IntPtr wParam, IntPtr lParam);

Затем отправьте WM_CLOSE сообщение в главное окно:

SendMessage((IntPtr)excel.Hwnd, 0x10, IntPtr.Zero, IntPtr.Zero);
0
ответ дан Kevin Vuilleumier 24 August 2018 в 07:07
поделиться

У меня была такая же проблема, мы можем решить проблему без какого-либо убийства, мы всегда забываем закрыть интерфейсы, которые мы использовали в классе Microsoft.Office.Interop.Excel, так что вот фрагмент кода и следуйте структуре и образом очистились объекты, также следите за интерфейсом «Листы» в коде, это главный виновник, который мы часто закрываем приложением, рабочей книгой, книгами, диапазоном, листом, но мы забываем или неосознанно не выпускаем объект «Листы» или используемый интерфейс, поэтому вот код:

               Microsoft.Office.Interop.Excel.Application app = null;
        Microsoft.Office.Interop.Excel.Workbooks books = null;
        Workbook book = null;
        Sheets sheets = null;
        Worksheet sheet = null;
        Range range = null;

        try
        {
            app = new Microsoft.Office.Interop.Excel.Application();
            books = app.Workbooks;
            book = books.Add();
            sheets = book.Sheets;
            sheet = sheets.Add();
            range = sheet.Range["A1"];
            range.Value = "Lorem Ipsum";
            book.SaveAs(@"C:\Temp\ExcelBook" + DateTime.Now.Millisecond + ".xlsx");
            book.Close();
            app.Quit();
        }
        finally
        {
            if (range != null) Marshal.ReleaseComObject(range);
            if (sheet != null) Marshal.ReleaseComObject(sheet);
            if (sheets != null) Marshal.ReleaseComObject(sheets);
            if (book != null) Marshal.ReleaseComObject(book);
            if (books != null) Marshal.ReleaseComObject(books);
            if (app != null) Marshal.ReleaseComObject(app);
        }
0
ответ дан kki 24 August 2018 в 07:07
поделиться

Вот фрагмент кода, который я написал, потому что у меня была такая же проблема, как и вы. В принципе, вам нужно закрыть книгу, выйти из приложения, а затем освободить ВСЕ ваши COM-объекты (а не только объект приложения Excel). Наконец, вызовите сборщик мусора для хорошей меры.

    /// <summary>
    /// Disposes the current <see cref="ExcelGraph" /> object and cleans up any resources.
    /// </summary>
    public void Dispose()
    {
        // Cleanup
        xWorkbook.Close(false);
        xApp.Quit();

        // Manual disposal because of COM
        while (Marshal.ReleaseComObject(xApp) != 0) { }
        while (Marshal.ReleaseComObject(xWorkbook) != 0) { }
        while (Marshal.ReleaseComObject(xWorksheets) != 0) { }
        while (Marshal.ReleaseComObject(xWorksheet) != 0) { }
        while (Marshal.ReleaseComObject(xCharts) != 0) { }
        while (Marshal.ReleaseComObject(xMyChart) != 0) { }
        while (Marshal.ReleaseComObject(xGraph) != 0) { }
        while (Marshal.ReleaseComObject(xSeriesColl) != 0) { }
        while (Marshal.ReleaseComObject(xSeries) != 0) { }
        xApp = null;
        xWorkbook = null;
        xWorksheets = null;
        xWorksheet = null;
        xCharts = null;
        xMyChart = null;
        xGraph = null;
        xSeriesColl = null;
        xSeries = null;

        GC.Collect();
        GC.WaitForPendingFinalizers();
    }
14
ответ дан qJake 24 August 2018 в 07:07
поделиться

Правила - никогда больше не используйте одну точку

- одну точку

var range = ((Range)xlWorksheet.Cells[rowIndex, setColumn]);
var hyperLinks = range.Hyperlinks;
hyperLinks.Add(range, data);

- Две или более точки

 (Range)xlWorksheet.Cells[rowIndex, setColumn]).Hyperlinks.Add(range, data);

- - Пример

 using Microsoft.Office.Interop.Excel;

 Application xls = null;
 Workbooks workBooks = null;
 Workbook workBook = null;
 Sheets sheets = null;
 Worksheet workSheet1 = null;
 Worksheet workSheet2 = null;

 workBooks = xls.Workbooks;
 workBook = workBooks.Open(workSpaceFile);
 sheets = workBook.Worksheets;
 workSheet1 = (Worksheet)sheets[1];


// removing from Memory
 if (xls != null)
 {    
   foreach (Microsoft.Office.Interop.Excel.Worksheet sheet in sheets)
   {
      ReleaseObject(sheet);
   }

   ReleaseObject(sheets);
   workBook.Close();
   ReleaseObject(workBook);
   ReleaseObject(workBooks);

   xls.Application.Quit(); // THIS IS WHAT IS CAUSES EXCEL TO CLOSE
   xls.Quit();
   ReleaseObject(xls);

   sheets = null;
   workBook = null;
   workBooks = null;
   xls = null;

   GC.Collect();
   GC.WaitForPendingFinalizers();
   GC.Collect();
   GC.WaitForPendingFinalizers();
}
9
ответ дан SztupY 24 August 2018 в 07:07
поделиться

Сложно избавиться от всех ссылок, поскольку вам нужно угадать, если такие вызовы:

var workbook = excel.Workbooks.Open("")

Создает экземпляр Workbooks, на который вы не ссылаетесь.

Даже такие ссылки, как:

targetRange.Columns.AutoFit()

Создают экземпляр .Columns(), если вы не знаете и не освобождены должным образом.

В итоге я написал класс, содержащий список ссылок на объекты, которые могли бы распоряжаться всеми объектами в обратном порядке.

Класс имеет список объектов и Add() функций для всего, что вы ссылаетесь при использовании Excel interop, который возвращает сам объект:

    public List<Object> _interopObjectList = new List<Object>();

    public Excel.Application add(Excel.Application obj)
    {
        _interopObjectList.Add(obj);
        return obj;
    }

    public Excel.Range add(Excel.Range obj)
    {
        _interopObjectList.Add(obj);
        return obj;
    }

    public Excel.Workbook add(Excel.Workbook obj)
    {
        _interopObjectList.Add(obj);
        return obj;
    }

    public Excel.Worksheet add(Excel.Worksheet obj)
    {
        _interopObjectList.Add(obj);
        return obj;
    }

    public Excel.Worksheets add(Excel.Worksheets obj)
    {
        _interopObjectList.Add(obj);
        return obj;
    }

    public Excel.Sheets add(Excel.Sheets obj)
    {
        _interopObjectList.Add(obj);
        return obj;
    }


    public Excel.Workbooks add(Excel.Workbooks obj)
    {
        _interopObjectList.Add(obj);
        return obj;
    }

Затем, чтобы отменить регистрацию объектов, я использовал следующий код:

    //Release all registered interop objects in reverse order
    public void unregister()
    {
        //Loop object list in reverse order and release Office object
        for (int i=_interopObjectList.Count-1; i>=0 ; i -= 1)
        { ReleaseComObject(_interopObjectList[i]); }

        //Clear object list
        _interopObjectList.Clear();
    }


    /// <summary>
    /// Release a com interop object 
    /// </summary>
    /// <param name="obj"></param>
     public static void ReleaseComObject(object obj)
     {
         if (obj != null && InteropServices.Marshal.IsComObject(obj))
             try
             {
                 InteropServices.Marshal.FinalReleaseComObject(obj);
             }
             catch { }
             finally
             {
                 obj = null;
             }

         GC.Collect();
         GC.WaitForPendingFinalizers();
         GC.Collect();
         GC.WaitForPendingFinalizers();
     }

Тогда принцип состоит в том, чтобы создать класс и зафиксировать ссылки следующим образом:

//Create helper class
xlsHandler xlObj = new xlsHandler();

..

//Sample - Capture reference to excel application
Excel.Application _excelApp = xlObj.add(new Excel.Application());

..
//Sample - Call .Autofit() on a cell range and capture reference to .Columns() 
xlObj.add(_targetCell.Columns).AutoFit();

..

//Release all objects collected by helper class
xlObj.unregister();

Not возможно, код большой красоты, но может вдохновить на что-то полезное.

5
ответ дан umlcat 24 August 2018 в 07:07
поделиться
Другие вопросы по тегам:

Похожие вопросы: