2012-09-21 18 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); 
}