2012-09-21 40 views
2

我想獲得的數據形成通過這種方式列出一個Excel文件中的列:數據後關閉Excel應用程序已被提取

private void Form1_Load(object sender, EventArgs e) 
     { 
      Excel.Application xlApp = new Excel.Application(); 
      Excel.Workbook xlWorkbook = xlApp.Workbooks.Open(@"D:/test.xlsx"); 
      Excel.Worksheet xlWorksheet = xlWorkbook.Sheets[1]; 
      Excel.Range xlRange = xlWorksheet.UsedRange; 

      int rowCount = xlRange.Rows.Count; 
      int colCount = xlRange.Columns.Count; 

      List<string> FirstColumnValues = new List<string>(); 
      List<string> SecondColumnValues = new List<string>(); 

      for (int row=1; row <= rowCount; row++) 
      { 
       for (int col = 1; col <= colCount; col++) 
       { 
        switch (col) 
        { 
         case 1: 
          FirstColumnValues.Add(xlRange.Cells[row, col].Value2.ToString()); 
          break; 
         case 2: 
          SecondColumnValues.Add(xlRange.Cells[row, col].Value2.ToString()); 
          break; 
        } 
       } 
      } 

      if (FirstColumnValues.Count != 0 && SecondColumnValues.Count != 0) 
      { 
       xlWorkbook.Close(); 
       xlApp.Quit(); 
       MessageBox.Show("Completed"); 
       Marshal.ReleaseComObject(xlRange); 
       Marshal.ReleaseComObject(xlWorksheet); 
       Marshal.ReleaseComObject(xlWorkbook); 
       Marshal.ReleaseComObject(xlApp); 
       xlApp = null; 
      } 
     } 

的問題是,這個過程EXCEL.EXE不打烊連我已經嘗試過所有的東西來正確地關閉它。我知道在這裏發佈了許多關於正確結束Excel過程的問題。但我不是專業人士,我已經嘗試了幾乎所有我能做的事情。 仍然沒有運氣。

那麼,有誰能告訴我這段代碼有什麼問題嗎?當所有數據都存儲在列表中時,過程如何關閉一次?

回答

1

我以前去過那裏。下面是一篇文章,說真的幫我整理出來:

http://devcity.net/Articles/239/1/article.aspx

的Excel似乎是關於終止進程非常頑固。你很可能最終會使用System.Diagnostics.Process來終止進程。

+0

感謝您的回覆,是的,我已經使用了'System.Diagnostics.Process'方法來關閉正在運行的進程。但它會關閉進程列表中的所有excel進程。是否有一種方法可以關閉由'new Excel.Application()'啓動的唯一進程。 ?? – ygssoni

+0

如果您不介意跟蹤正在運行的進程,則可以在開始運行COM之前獲取excel進程的列表,然後再開始運行。這會給你與COM對象相關的進程,而不會太混亂。你只需要確保你不會在單獨的線程上啓動2個或更多的COM實例,否則這種技術將無法工作。 –

+1

Ohk,聽起來不錯。如果我沒有得到任何直接或短的方法,我會肯定地嘗試。謝謝!:) – ygssoni

3

我知道這個問題已經被回答,但我想我會分享我發現試圖解決同樣的問題。希望有人會覺得這很有用。這是在vb.net,但我相信它可以被翻譯。

Dim proc As System.Diagnostics.Process 
     For Each proc In System.Diagnostics.Process.GetProcessesByName("EXCEL") 
      If proc.MainWindowTitle.ToString = "" Then 
       proc.Kill() 
      End If 
     Next 

我發現,當我是通過我的應用程序打開Excel文件窗口標題爲空,所以不要關每運行Excel過程我剛剛關閉的,沒有標題的人。

編輯:

如果你要終止的進程,因爲你不能找到left over variables that haven't been cleaned up(你使用兩個點設置基本上任何變量),那麼至少殺死了正確的Excel實例:

[DllImport("user32.dll", SetLastError = true)] 
private static extern int GetWindowThreadProcessId(IntPtr hwnd, ref int lpdwProcessId); 

... 

if (xlApp != null) 
{ 
    GetWindowThreadProcessId(new IntPtr(xlApp.Hwnd), ref excelProcessId); 

    Process ExcelProc = Process.GetProcessById(excelProcessId); 
    if (ExcelProc != null) 
    { 
    ExcelProc.Kill(); 
    } 

我不主張殺進程,必須先清理與VSTO的Contrib,如:

using (var xlApp = new Microsoft.Office.Interop.Excel.Application().WithComCleanup()) 
+0

-1這是非常糟糕的做法。 –

+0

這是爲什麼?這似乎是結束這一過程的唯一方法 – Lift

1

確保運行Excel實例最簡單的方法最終會終止(即當你的應用程序退出時)是將最高級別的對象封裝在try/finally塊中。

Excel.Application xlApp; 
try{ 
    xlApp = new Excel.Application(); 
    ...do some work... 
} 
finally{ 
    xlApp.DisableAlerts=True; 
    xlApp.Quit(); 
    xlApp.DisableAlerts=False; 
    Marshal.ReleaseComObject(xlApp); 
} 

//If you don't mind having the Excel process kept alive for a while, 
//you don't even have to call ReleaseComObject() on the intermediate objects. 
//The runtime will eventually free the underlying COM objects. 

//If you want to clean up right away, your bookkeeping needs to be more thorough. 
//Every time you access a method or property that returns a runtime callable wrapper 
//(System.__ComObject), you'll need to assign them to a variable 
//and make sure Marshal.ReleaseComObject() is called. 

// More thorough bookkeeping...  
Excel.Application xlApp; 
try{ 
    xlApp = new Excel.Application(); 

    Excel.Workbooks xlWorkbooks = xlApp.Workbooks; 
    Excel.Workbook xlWorkbook = xlWorkbooks.Open(@"D:/test.xlsx"); 
    Excel.Sheets xlSheets = xlWorkbook.Sheets; 
    Excel.Worksheet xlWorksheet = xlSheets[1]; 
    Excel.Range xlRange = xlWorksheet.UsedRange; 

    ...inside the loop... 
    Excel.Range xlCell = xlRange.Cells[row, col]; 
    FirstColumnValues.Add(xlCell.Value2.ToString()); 
    Marshal.ReleaseComObject(xlCell); 

    ...inside the loop... 
    Excel.Range xlCell = xlRange.Cells[row, col]; 
    SecondColumnValues.Add(xlCell.Value2.ToString()); 
    Marshal.ReleaseComObject(xlCell); 

    ...do more work... 

    ...clean up... 
    Marshal.ReleaseComObject(xlRange); 
    Marshal.ReleaseComObject(xlWorksheet); 
    Marshal.ReleaseComObject(xlSheets); 
    Marshal.ReleaseComObject(xlWorkbook); 
    Marshal.ReleaseComObject(xlWorkbooks); 
} 
finally{ 
    xlApp.DisableAlerts=True; 
    xlApp.Quit(); 
    xlApp.DisableAlerts=False; 
    Marshal.ReleaseComObject(xlApp); 
}