2012-01-23 1 views
6

디버깅 중 일부 코드에 문제가 있습니다. Excel interop은 통합 문서에서 일부 값을 추출하는 데 사용됩니다. 그러나 Excel은 프로그램이 종료 된 후에도 열어 둡니다. 나는 기존의 솔루션을 시도했습니다,하지만 여전히 코드 ( Excel 프로세스는 interop 후에 열려 있습니다. 전통적인 방법이 작동하지 않습니다.

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); 
    } 

심지어 코드의 간단한 조각이 여러 개의 파일을 실행하는 과정을 계속 실행되는 모든 시스템에서 열려있는 엑셀에 대한 참조를 유지 XLSM, XLSX, xls). 지금 당장 우리가 열어 둔 Excel 프로세스를 죽일 수있는 해결 방법이 있지만, 오히려 내 자신의 정신으로이 일을하는 것이 좋습니다.

변수를 Workbook으로 좁히도록 추가해야합니다. books.Open()에 대한 호출을 제거하고 book에 대한 모든 참조를 제거하면 성공적으로 닫힙니다.

+0

테스트했을 때 코드가 작동했는데 런타임에 예외가 발생하여 문제가 발생 했습니까? – msmucker0527

답변

11

이 나를 위해 성공적으로 일했다),이 코드에 명백한 문제를 지적 자유롭게, 난 정말 지금까지 COM-글을 읽고되는입니다

// 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(); 
} 
+2

이것이 올바른 답변으로 표시되었습니다. 그것은 여전히 ​​내 dev 컴퓨터에서 작동하지 않지만, 이것은 깨끗한 설치 또는 내 집 컴퓨터에서 작동합니다. 이상한. – bradenb

3

저는 전 COM 아마추어입니다. 아주 오래 전 한 프로젝트에서 사소한 것으로 사용했지만, 여기에 제가 사용한 스 니펫이 있습니다. 나는 어딘가 온라인에서 그것을 발견했을 것이다. 기억하지 마라. 어떤 경우에, 나는 그것의 한창 붙여 넣기) 내가 지금 그것을 밖으로 시도 드릴 수 없습니다

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(); 
     } 
    } 
} 

을하지만, 아마 (솔직히) 모든 세부 사항을 기억하지 않는다했다. 어쩌면 그것은 당신을 도울 것입니다.

 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(); 
+1

이 작업은 부분적으로 GC.Collect()가 마지막에 catch catch에 포함되어 있기 때문에 부분적으로 작동합니다. 그러나 마지막 부분에 도달하기 전에는 실제로 닫히지 않습니다. 왜 ? 시트/시트/워크 북을 전달하거나 함수를 능가하면 개체가 값으로 전달되기 때문입니다. COM 값은 개체 자체에 대한 작업과 상관없이 동일하게 유지됩니다. 이러한 COM 객체를 참조로 전달할 수 없으면 시도했지만 시도하지 않았습니다. –

2

이 내가이 문제를 해결 있어요 방법은 다음과 같습니다 :

0

이 코드는 저에게 적합합니다.

//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에는이 문제와 관련하여 좋은 정보가 있습니다.