Excel 2007 зависает при закрытии через .NET - PullRequest
1 голос
/ 29 октября 2008

У меня есть программа Visual Basic .NET, которая должна открывать и закрывать электронную таблицу Excel. Открытие и чтение электронной таблицы работают нормально, но попытка закрыть приложение Excel 2007 приводит к зависанию. Кажется, закрывается, но если вы посмотрите в диспетчере задач, приложение все еще работает. Код, который я использую, чтобы закрыть это

wbkData.Close(saveChanges:=False)
appExcel.Quit()
wbkData = Nothing
appExcel = Nothing

Как я могу правильно закрыть Excel?

Ответы [ 3 ]

5 голосов
/ 29 октября 2008

Ответ на ваш вопрос был рассмотрен здесь, я думаю: Как правильно очистить объекты взаимодействия Excel в c

Я не могу видеть из вашего примера кода, но в основном всегда присваиваю ваши объекты Excel локальным переменным, никогда не опуская «две точки вниз», как это:

//FAIL

Workbook wkBook = xlApp.Workbooks.Open(@"C:\mybook.xls");

вместо ссылки на каждый объект в отдельности:

//WIN

Worksheets sheets = xlApp.Worksheets;
Worksheet sheet = sheets.Open(@"C:\mybook.xls");
...
Marshal.ReleaseComObject(sheets);
Marshal.ReleaseComObject(sheet);

.NET создает оболочку для COM-объекта, которая невидима для вас и не освобождается до тех пор, пока GC не сотворит свою магию.

Пока я не обнаружил это, я запускал приведенный ниже хакерский код в приложении ASP.NET каждый раз, когда создавал новую рабочую книгу, которая проверяет возраст процесса excel.exe и убивает все, которые старше минуты:

//force kill any excel processes over one minute old.
try
{
    Process[] procs = Process.GetProcessesByName("EXCEL");
    foreach (Process p in procs)
    {
        if (p.StartTime.AddMinutes(1) < DateTime.Now)
        {
            p.Kill(); 
        }  
    }  
}
catch (Exception)
{}  
1 голос
/ 30 октября 2008

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

Я также обсуждал эту проблему ранее в StackOverflow для вопроса Как правильно очистить объекты взаимодействия Excel в C # .

Первый ответ на этот вопрос был помечен как «правильный» и набрал 11 голосов, но я вас уверяю, что эту политику крайне сложно правильно использовать на практике. Если кто-то когда-нибудь проскальзывает и использует «две точки», или итерирует ячейки через цикл для каждого цикла или любой другой подобный вид команды, то у вас будут COM-объекты без ссылок и вы рискуете зависнуть - и не будет никакого способа найти причину этого в коде.

Вместо этого процедура очистки, которую вы принимаете, определенно является подходящим.

0 голосов
/ 29 октября 2008

Я нашел решение в блоге MSDN Excel , которое мне помогло. Это объясняется как

Существует две проблемы, описанные выше:

(1) Хотя код сначала удалите объект 'wbkData', и т. д. приведенный выше код на самом деле не принудительно , так как процедура .NET Garbage Collection может избавиться от его объекты в любом порядке. (GC является недетерминированный по порядку, а не просто недетерминированный во времени.)

(2) Такие команды, как 'wsh = wbkData.Workssheets.Item (1) '- или линии, как это - очень распространены и создаст объект RCW, оборачивающий Объект «Рабочие листы». У тебя не будет переменная, содержащая ссылку на нее, так ты вообще не думаешь об этом, но этот объект RCW не будет утилизировать до следующего мусора Коллекция. Тем не менее, код выше вызывает GC.Collect () last , и поэтому RCW все еще держит ссылку на этот объект «Рабочие листы», когда appExcel.Quit () вызывается. Excel зависает в результате.

Окончательный код выглядит как

GC.Collect()
GC.WaitForPendingFinalizers()

wbkData.Close(SaveChanges:=False)
System.Runtime.InteropServices.Marshal.FinalReleaseComObject(wbkData) : wbkData = Nothing
appExcel.Quit()
System.Runtime.InteropServices.Marshal.FinalReleaseComObject(appExcel) : appExcel = Nothing
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...