2013-08-09 2 views
7

У меня есть эта программа на C#, которая никогда не закрывает процесс Excel. В основном он находит количество экземпляров строки в формате Excel. Я пробовал всевозможные вещи, но он не работает. Существует форма, вызывающая этот метод, но это не должно меняться, почему процесс не закрывается. Я смотрю предложения Ханса Пассана, но никто не работает.Процесс Excel не закрывается

EDIT: Я попробовал упомянутые вещи, и он все равно не будет закрыт. Вот мой обновленный код. EDIT: Пробовал весь процесс Process.Kill(), и это работает, но это похоже на взломать что-то, что должно просто работать.

public class CompareHelper 
{ 
    // Define Variables 
    Excel.Application excelApp = null; 
    Excel.Workbooks wkbks = null; 
    Excel.Workbook wkbk = null; 
    Excel.Worksheet wksht = null; 
    Dictionary<String, int> map = new Dictionary<String, int>(); 

    // Compare columns 
    public void GetCounts(string startrow, string endrow, string columnsin, System.Windows.Forms.TextBox results, string excelFile) 
    { 
     results.Text = ""; 

     try 
     { 
      // Create an instance of Microsoft Excel and make it invisible 
      excelApp = new Excel.Application(); 
      excelApp.Visible = false; 

      // open a Workbook and get the active Worksheet 
      wkbks = excelApp.Workbooks; 
      wkbk = wkbks.Open(excelFile, Type.Missing, true); 
      wksht = wkbk.ActiveSheet; 
      ... 

     } 
     catch 
     { 
      throw; 
     } 
     finally 
     { 
      GC.Collect(); 
      GC.WaitForPendingFinalizers(); 

      if (wksht != null) 
      { 
       //wksht.Delete(); 
       Marshal.FinalReleaseComObject(wksht); 
       wksht = null; 
      } 

      if (wkbks != null) 
      { 
       //wkbks.Close(); 
       Marshal.FinalReleaseComObject(wkbks); 
       wkbks = null; 
      } 

      if (wkbk != null) 
      { 
       excelApp.DisplayAlerts = false; 
       wkbk.Close(false, Type.Missing, Type.Missing); 
       Marshal.FinalReleaseComObject(wkbk); 
       wkbk = null; 
      } 

      if (excelApp != null) 
      { 
       excelApp.Quit(); 
       Marshal.FinalReleaseComObject(excelApp); 
       excelApp = null; 
      } 

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

      /* 
      Process[] processes = Process.GetProcessesByName("EXCEL"); 
      foreach (Process p in processes) 
      { 
       p.Kill(); 
      } 
      */ 
     } 
    } 
} 
+0

Меньшая репро поможет. Во всяком случае, я запускал это на своей машине, и Excel закрывается просто отлично. У вас установлены некорректные надстройки Excel? Попробуйте удалить их один за другим, чтобы увидеть, влияет ли это на способность Excel отключиться. –

+0

Я пробовал ванильный процесс Excel, и он все еще не закрывался.Я использую форму в качестве интерфейса для вызова этого класса, может ли это что-то сделать, чтобы открыть Excel? – user1017719

+0

На самом деле это третий ответ, который, я думаю, вам понадобится из приведенной выше ссылки. – devuxer

ответ

3

Вот интересная база знаний по теме офисных приложений, которые остаются открытыми после того, как приложение .NET отключится от них.

Office application does not quit after automation from Visual Studio .NET client

Примеры кода находятся в ссылке (vb.net извините). В основном это показывает, как правильно настроить и снести офисное приложение, чтобы оно закрывалось, когда вы закончили с ним.

System.Runtime.InteropServices.Marshal.FinalReleaseComObject, где происходит волшебство.

EDIT: Вам необходимо вызвать FinalReleaseComObject для каждого объекта excel, который вы создали.

if (excelWorkSheet1 != null) 
{ 
    Marshal.FinalReleaseComObject(excelWorkSheet1); 
    excelWorkSheet1 = null; 
} 
if (excelWorkbook != null) 
{ 
    Marshal.FinalReleaseComObject(excelWorkbook); 
    excelWorkbook = null; 
} 
if (excelApp != null) 
{ 
    Marshal.FinalReleaseComObject(excelApp); 
    excelApp = null; 
} 
+0

Я пробовал этот метод, и он не работает. Есть ли ресурс, который не будет выпущен, который хранит Excel открытым? – user1017719

+0

Да, есть RCW «Runtime Callable Wrapper», который заставит процесс оставаться активным, если он не будет выпущен в приложении .NET. – JeremiahDotNet

+0

Я тоже пробовал этот метод, и он тоже не работал для меня. –

0

Я, наконец, получил его, чтобы закрыть. Вам нужно добавить переменную для коллекции Workbooks, а затем использовать FinalReleaseComObject, как указано в других ответах. Я предполагаю, что каждый возможный объект COM Excel, который вы используете, должен быть удален таким образом.

try 
     { 
      // Create an instance of Microsoft Excel and make it invisible 
      excelApp = new Excel.Application(); 
      excelApp.DisplayAlerts = false; 
      excelApp.Visible = false; 

      // open a Workbook and get the active Worksheet 

      excelWorkbooks = excelApp.Workbooks; 
      excelWorkbook = excelWorkbooks.Open(excelFile, Type.Missing, true); 
      excelWorkSheet1 = excelWorkbook.ActiveSheet; 

     } 
     catch 
     { 
      throw; 
     } 
     finally 
     { 

      NAR(excelWorkSheet1); 
      excelWorkbook.Close(false, System.Reflection.Missing.Value, System.Reflection.Missing.Value); 
      NAR(excelWorkbook); 
      NAR(excelWorkbooks); 
      excelApp.Quit(); 
      NAR(excelApp); 

     } 
    } 
    private void NAR(object o) 
    { 
     try 
     { 
      System.Runtime.InteropServices.Marshal.FinalReleaseComObject(o); 
     } 
     catch { } 
     finally 
     { 
      o = null; 
     } 
    } 
+0

Я пробовал это, и он все еще не работает. Есть ли способ найти идентификатор процесса excelApp и просто убить его? – user1017719

+0

Вы можете добавить это в случаях, когда вы останавливаете Excel во время отладки/сбоя. Но это не рекомендуется для нормального использования. Комментируйте разделы и устраняйте неполадки в том, какой раздел вам дает проблему. –

+0

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

1

DotNet выпускает COM-объект только после того, как все ручки были выпущены. То, что я делаю, это прокомментировать все, а затем добавить часть. Посмотрите, выпускает ли он Excel. Если это не соответствует следующим правилам. Когда он будет выпущен, добавьте больше кода, пока он не будет выпущен снова.

1) При создании переменной Excel, установить все значения NULL (это избегает не инициировало ошибок)

2) Не используйте переменные, не отпуская ее первым Marshal.FinalReleaseComObject

3) Не сгибай точка (a.b = z). dotNet создает временную переменную, которая не будет выпущена.

c = a.b; 
c = z; 
Marshal.FinalReleaseComObject(c); 

4) Освободить все переменные excel. Чем быстрее, тем лучше.

5) Установите его обратно в NULL.

Установить культуру в «en-US». Есть ошибка, которая разбивает Excel с некоторыми культурами. Это гарантирует, что этого не произойдет.

Вот идея о том, что ваш код должен быть структурирован:

 thisThread.CurrentCulture = new System.Globalization.CultureInfo("en-US"); 
     InteropExcel.Application excelApp = null; 
     InteropExcel.Workbooks wkbks = null; 
     InteropExcel.Workbook wkbk = null; 
     try 
     { 
       excelApp = new InteropExcel.Application(); 
       wkbks = excelApp.Workbooks; 
       wkbk = wkbks.Open(fileName); 
... 

     } 
     catch (Exception ex) 
     { 
     } 

     if (wkbk != null) 
     { 
      excelApp.DisplayAlerts = false; 
      wkbk.Close(false); 
      Marshal.FinalReleaseComObject(wkbk); 
      wkbk = null; 
     } 

     if (wkbks != null) 
     { 
      wkbks.Close(); 
      Marshal.FinalReleaseComObject(wkbks); 
      wkbks = null; 
     } 

     if (excelApp != null) 
     { 
      // Close Excel. 
      excelApp.Quit(); 
      Marshal.FinalReleaseComObject(excelApp); 
      excelApp = null; 
     } 

     // Change culture back from en-us to the original culture. 
     thisThread.CurrentCulture = originalCulture;  
    } 
Смежные вопросы