Объект Microsoft.Interop не закрывается и не освобождается

Каждый раз, когда я запускаю этот код, объект не закрывается. У меня все еще есть excel.exe, работающий в диспетчере задач. Даже если я установлю объекты = null, все равно ничего. Я даже пытался использовать метод объектов .Quit().

Что я здесь делаю неправильно?

    private bool ValidateQM()
    {
        //setup the objects
        Excel.Application oXL = null;
        Excel.Workbook oWB = null;
        Excel.Worksheet oSheet = null;
        int hWnd = 0;

        try
        {

            //Start Excel and get Application object.
            oXL = new Excel.Application();
            hWnd = oXL.Application.Hwnd;
            oXL.Visible = false;

            //Open the workbook.
            oWB = oXL.Workbooks.Open(workingForm, 0, false, 5, "", "", false, Excel.XlPlatform.xlWindows, "",true, false, 0, true, false, false);

            //Get the Worksheet
            oSheet = oWB.Worksheets[1];

            //Check the date values

            string mydatetime = oSheet.Cells[5, 33].Text.ToString() + " " + oSheet.Cells[7, 33].Text.ToString();
            string dateofscore = oSheet.Cells[3, 12].Text.ToString();

            DateTime.Parse(mydatetime); //make my string a real boy
            DateTime.Parse(dateofscore);

            // Cleanup 
            GC.Collect();
            GC.WaitForPendingFinalizers();

            System.Runtime.InteropServices.Marshal.FinalReleaseComObject(oSheet);

            //oWB.Close();
            System.Runtime.InteropServices.Marshal.FinalReleaseComObject(oWB);

            //oXL.Quit();
            System.Runtime.InteropServices.Marshal.FinalReleaseComObject(oXL);

            return true;
        }

person CodingIsAwesome    schedule 02.03.2012    source источник
comment
Код нечестивый, смешивающий как автоматическое, так и ручное управление памятью, и в итоге не получается ни того, ни другого. Но это не работает, потому что вы отлаживаете сборку отладки. Существуют ссылки на скрытые объекты, созданные индексаторами Cells[,]. Они поддерживают Excel в рабочем состоянии до конца метода при отладке. Он будет работать в сборке Release без отладчика. Переместите большую часть кода в отдельный метод, чтобы улучшить результат.   -  person Hans Passant    schedule 03.03.2012


Ответы (3)


Вы не нарушаете правило "не использовать две точки" в строке hWnd = oXL.Application.Hwnd ? Дополнительные сведения об этом см. в разделе библиотеки взаимодействия Excel, несовместимые с ASP.NET?. .

person Akash    schedule 02.03.2012

Когда вы вызываете GC.Collect(), объекты oXL и oWB все еще находятся в области действия, поэтому для них активна ссылка. В результате GC.Collect() их не коснется. Если вы хотите, чтобы они были собраны мусором, установите для них значение null, чтобы при вызове GC.Collect() не было активных ссылок. Кроме того, вы можете вызвать Close() в активной книге и Quit() в приложении Excel. Вы также можете поместить все в свою область видимости с помощью фигурных скобок { }, чтобы все вместе вышло из области видимости.

        // Cleanup 
        oWB.Close(false);
        oWB = null;
        oXL.Quit();
        oXL = null;
        hWnd = null;
#if (DEBUG_SPEED_UP_GC)
        GC.Collect();
        GC.WaitForPendingFinalizers();
#endif

Изменить. Обратите внимание, что вызов сборки мусора вручную — плохая идея. Я предполагаю, что вы делаете это только в целях отладки, чтобы ускорить сбор мусора, поэтому я добавил #if.

person Ed Bayiates    schedule 02.03.2012
comment
Или, что еще лучше, не запускайте сборку мусора вручную, чтобы предотвратить множество неразрешимых ошибок. - person Cody Gray; 03.03.2012
comment
@ Коди, я предполагал, что он вызывает сборку мусора только для целей отладки. Согласитесь, было бы плохо как из-за ошибок, так и из соображений производительности делать это в живом приложении. - person Ed Bayiates; 05.03.2012
comment
Существует не так много веских причин для вызова сборки мусора в целях отладки, учитывая, что в противном случае вы никогда не будете этого делать. На самом деле, я не могу придумать ни одного (но как только я скажу «нет», кто-нибудь в ответ придумает какой-нибудь непонятный пограничный случай). Дело в том, что это не решает проблему. Кроме того, ваш ответ не дает понять, что вы действительно не должны этого делать, что я считаю ошибкой. - person Cody Gray; 05.03.2012

Я собираюсь предположить, что исключение не выбрасывается и обработчик catch, который вы не показываете, не делает ничего злонамеренного для целей вашей проблемы.

Я даже пытался использовать метод объекта Quit

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

//Start Excel and get Application object. oXL = new
Excel.Application();
hWnd = oXL.Application.Hwnd;
oXL.Visible = false;

Неважно, что вы меняете видимость окна, которым вы не владеете, что произойдет, если Excel отобразит предупреждение при выходе? Установка Visible на false в родительском окне скроет его от пользователя.

В целях отладки попробуйте не скрывать окно.

Здесь есть некоторая информация о том, что вы можете сделать так, чтобы Excel не выдавал предупреждения, которые в противном случае потребовали бы интерактивного внимания. Основная суть его:

DisplayAlerts = false
AskToUpdateLinks = false
AlertBeforeOverwriting = false
Interactive = false
Visible = false
FeatureInstall = 0 'msoFeatureInstallNone

Вы запускаете свое приложение внутри интерактивного пользовательского сеанса, верно? Поскольку все остальное не поддерживается:

В настоящее время Microsoft не рекомендует и не поддерживает автоматизацию приложений Microsoft Office из любого автоматического неинтерактивного клиентского приложения или компонента (включая ASP, ASP.NET, DCOM и службы NT), поскольку Office может демонстрировать нестабильное поведение и/или или взаимоблокировка при запуске Office в этой среде.

person ta.speot.is    schedule 02.03.2012