2012-01-23 12 views
6

Występuje problem z kodem, który debuguję. Excel interop służy do wyodrębniania niektórych wartości ze skoroszytu; jednak program Excel pozostaje otwarty po zakończeniu programu. Próbowałem tradycyjne rozwiązanie, ale wciąż zachowuje odwołanie do programu Excel otwarty na wszystkich komputerach, na których kod jest uruchamianyProces Excel pozostaje otwarty po współdziałaniu; tradycyjna metoda nie działa

private void TestExcel() 
    { 
     Excel.Application excel = new Excel.Application(); 
     Excel.Workbooks books = excel.Workbooks; 
     Excel.Workbook book = books.Open("C:\\test.xlsm"); 

     book.Close(); 
     books.Close(); 
     excel.Quit(); 

     Marshal.ReleaseComObject(book); 
     Marshal.ReleaseComObject(books); 
     Marshal.ReleaseComObject(excel); 
    } 

Nawet ten prosty kawałek kodu utrzymuje proces uruchomiony z wielu plików (xlsm, XLSX, xls). W tej chwili mamy obejście problemu, aby zabić procesy Excela, które otworzyliśmy, ale wolałbym, żeby to działało dla mojego własnego zdrowia psychicznego.

Powinienem dodać, że zawęziłem to do zmiennej Workbook. Jeśli usuniemy połączenie pod numer books.Open() i wszystkie odniesienia do book, to zostanie ono pomyślnie zamknięte.

+0

Twój kod zadziałał, gdy go przetestowałem, czy otrzymujesz wyjątek w czasie wykonywania, powodujący problem? – msmucker0527

Odpowiedz

11

ten z powodzeniem pracował dla mnie:

 xlApp.Quit(); 

     //release all memory - stop EXCEL.exe from hanging around. 
     if (xlWorkBook != null) { Marshal.ReleaseComObject(xlWorkBook); } //release each workbook like this 
     if (xlWorkSheet != null) { Marshal.ReleaseComObject(xlWorkSheet); } //release each worksheet like this 
     if (xlApp != null) { Marshal.ReleaseComObject(xlApp); } //release the Excel application 
     xlWorkBook = null; //set each memory reference to null. 
     xlWorkSheet = null; 
     xlApp = null; 
     GC.Collect(); 
+2

Oznaczono jako odpowiedź, ponieważ jest to poprawne. Chociaż nadal nie działa na moim komputerze, to działa na czystej instalacji lub na moich komputerach domowych. Dziwny. – bradenb

3

Jestem totalnie amatorskim amatorem, używam go do drobnych rzeczy w jednym projekcie dość dawno temu, ale tutaj jest urywek, którego tam użyłem. Prawdopodobnie znalazłem to gdzieś w Internecie, nie pamiętam. W każdym razie, ja wkleić pełnej krasie;)

public static class ComBlackBox 
{ 
    public static void ReleaseObject(object obj) 
    { 
     try 
     { 
      System.Runtime.InteropServices.Marshal.ReleaseComObject(obj); 
      obj = null; 
     } 
     catch (ArgumentException ex) 
     { 
      obj = null; 
      MessageBox.Show("Unable to release the Object " + ex.Message); 
     } 
     finally 
     { 
      GC.Collect(); 
     } 
    } 
} 

jestem w stanie go wypróbować teraz, ale to prawdopodobnie pracował (I szczerze nie pamiętam żadnych szczegółów). Może to ci pomoże. Krępuj się wskazać żadnych widocznych problemów z tym kodem, naprawdę jestem daleko od bycia COM-literat;)

+1

Ta praca częściowo dlatego, że masz GC.Collect() w końcu spróbować złapać na końcu. Jednak nie zamyka się tak dobrze, dopóki nie dojdzie do końca. Czemu ? ponieważ obiekt jest przekazywany przez wartość, jeśli przekazujesz arkusz/arkusze/skoroszyt lub excel do funkcji. Ich wartości COM pozostaną takie same, bez względu na to, co zrobisz z samym obiektem. Chyba że możesz przekazać ten obiekt COM przez odniesienie, ale próbowałem go i nie pozwalał mi. –

2

To jak mam sobie z tym problemem:

// Store the Excel processes before opening. 
Process[] processesBefore = Process.GetProcessesByName("excel"); 

// Open the file in Excel. 
Application excelApplication = new Application(); 
Workbook excelWorkbook = excelApplication.Workbooks.Open(Filename); 

// Get Excel processes after opening the file. 
Process[] processesAfter = Process.GetProcessesByName("excel"); 

// Now find the process id that was created, and store it. 
int processID = 0; 
foreach (Process process in processesAfter) 
{ 
    if (!processesBefore.Select(p => p.Id).Contains(process.Id)) 
    { 
     processID = process.Id; 
    } 
} 

// Do the Excel stuff 

// Now close the file with the COM object. 
excelWorkbook.Close(); 
excelApplication.Workbooks.Close(); 
excelApplication.Quit(); 

// And now kill the process. 
if (processID != 0) 
{ 
    Process process = Process.GetProcessById(processID); 
    process.Kill(); 
} 
0

Ten kod działa dla mnie.

//Declare separate object variables 
Excel.Application xlApp = new Excel.Application(); 
Excel.Workbooks xlWorkbooks = xlApp.Workbooks; 
Excel.Workbook xlWorkbook = xlWorkbooks.Add(Missing.Value); 
Excel.Worksheet xlWorksheet = (Excel.Worksheet)xlWorkbook.Worksheets.get_Item(1); 

//Create worksheet 

xlWorkbook.Close(false, Missing.Value, Missing.Value); 
xlWorkbooks.Close(); 
xlApp.Quit(); 

Marshal.FinalReleaseComObject(xlWorksheet); 
Marshal.FinalReleaseComObject(xlWorkbook); 
Marshal.FinalReleaseComObject(xlWorkbooks); 
Marshal.FinalReleaseComObject(xlApp); 

xlWorksheet = null; 
xlWorkbook = null; 
xlWorkbooks = null; 
xlApp = null; 

GC.Collect(); 

This article from Microsoft ma kilka dobrych informacji dotyczących tego problemu.

Powiązane problemy