2012-01-23 28 views
6

Tôi đang gặp sự cố với một số mã tôi đang gỡ lỗi. Excel interop được sử dụng để trích xuất một số giá trị từ một bảng tính; tuy nhiên, Excel vẫn mở sau khi chương trình đã thoát. Tôi đã thử các giải pháp truyền thống, nhưng nó vẫn giữ một tham chiếu đến Excel mở trên tất cả các máy nơi mã được chạyQuá trình Excel vẫn mở sau khi interop; phương pháp truyền thống không hoạt động

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

Ngay cả mảnh này mã đơn giản giữ cho quá trình chạy với nhiều file (xlsm, xlsx, xls). Ngay bây giờ chúng ta có một giải pháp thay thế để giết các quy trình Excel mà chúng ta đã mở ra, nhưng tôi muốn làm việc này cho sự tỉnh táo của chính mình hơn.

Tôi nên thêm rằng tôi đã thu hẹp nó xuống biến số Workbook. Nếu tôi xóa cuộc gọi đến books.Open() và tất cả các tham chiếu đến book thì nó sẽ đóng thành công.

+0

Mã của bạn đã hoạt động khi tôi thử nghiệm, bạn có thể nhận được ngoại lệ vào thời gian chạy gây ra sự cố không? – msmucker0527

Trả lời

11

này đã làm việc thành công cho tôi:

 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

Được đánh dấu là câu trả lời vì điều này là chính xác. Mặc dù nó vẫn không hoạt động trên máy dev của tôi, nó hoạt động trên một cài đặt sạch hoặc trên máy tính gia đình của tôi. Odd. – bradenb

3

Tôi là một tổng cộng COM nghiệp dư, sử dụng nó cho một điều nhỏ trong một dự án khá lâu trước đây, nhưng đây là một đoạn tôi sử dụng ở đó. Tôi có thể tìm thấy nó ở đâu đó trực tuyến, không nhớ. Trong mọi trường hợp, tôi dán nó vinh quang đầy đủ của nó;)

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

Tôi không thể dùng thử ngay bây giờ, nhưng nó có thể hoạt động (tôi thành thật không nhớ chi tiết). Có lẽ nó sẽ giúp bạn ra ngoài. Cảm thấy tự do để chỉ ra bất kỳ vấn đề rõ ràng với mã này, tôi thực sự là xa là COM-biết chữ;)

+1

Công việc này một phần vì bạn có GC.Collect() ở cuối cùng thử bắt ở cuối. Tuy nhiên, nó không thực sự đóng excel cho đến khi nó được đến phần cuối cùng. Tại sao ? bởi vì bạn đối tượng được truyền theo giá trị, nếu bạn chuyển trang tính/trang tính/sổ làm việc hoặc vượt trội vào hàm. Giá trị COM của chúng sẽ giữ nguyên, bất kể bạn làm gì với chính đối tượng đó. Trừ khi bạn có thể vượt qua các đối tượng COM bằng cách tham khảo, nhưng tôi đã thử nó, và nó sẽ không cho tôi. –

2

Đây là cách tôi giải quyết vấn đề này:

// 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

Mã này phù hợp với tôi.

//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 có một số thông tin tốt về vấn đề này.

Các vấn đề liên quan