2012-05-19 53 views
2

我工作的一個項目,我需要在Excel中一些工作流程自動化和我打了一個非常討厭的障礙。在該項目中,我使用Visual Studio Tools For Office創建文檔級加載項。用戶使用作爲該項目一部分的功能區控件來自動複製項目外部工作簿中的工作表。外部工作簿從SQL blob加載並寫入磁盤。外接程序代碼打開每個工作簿,將工作表複製到加載項工作簿中,然後關閉該外部工作簿。通常,第一個工作簿可以正常工作,但打開後續工作簿將引發AccessViolationException。AccessViolationException在ThisWorkbook.Application.Workbooks.Open

public void AddSheetFromTempFile(string tempfilePath) 
    { 
     Sheets sheets = null; 
     Excel.Workbook workbook = null; 
     Excel.Workbooks books = null; 
     try 
     { 
      books = this.Application.Workbooks; 

      //Throws AccessViolationException 
      workbook = books.Open(tempfilePath, 0, true, 5, 
       String.Empty, String.Empty, true, XlPlatform.xlWindows, 
       String.Empty, true, false, 0, true, true, false); 

      sheets = workbook.Worksheets; 

      sheets.Copy(After: this.GetLastWorksheet()); 

      workbook.Close(SaveChanges: false); 
     } 
     finally 
     { 
      if (sheets != null) 
      { 
       Marshal.FinalReleaseComObject(sheets); 
      } 

      if (workbook != null) 
      { 
       Marshal.FinalReleaseComObject(workbook); 
      } 

      if (books != null) 
      { 
       Marshal.FinalReleaseComObject(books); 
      } 

      GC.Collect(); 
      GC.WaitForPendingFinalizers(); 
     } 
    } 

    //extension method for getting last worksheet 
    public static Microsoft.Office.Interop.Excel.Worksheet 
    GetLastWorksheet(this Microsoft.Office.Tools.Excel.WorkbookBase workbook) 
    { 
     int veryHiddenSheets = 0; 

     foreach(Worksheet sheet in workbook.Worksheets) 
     { 
      if(sheet.Visible == XlSheetVisibility.xlSheetVeryHidden) 
      { 
       veryHiddenSheets++; 
      } 
     } 
     int lastIndex = workbook.Worksheets.Count - veryHiddenSheets; 
     return workbook.Worksheets[lastIndex]; 
    } 

所以我已經將問題縮小到一組可重複的步驟。此問題似乎源於您向工作簿中添加N張圖紙,然後刪除它們並重新添加圖紙的情況。我啓用了本地調試,在此建議http://social.msdn.microsoft.com/forums/en-US/vsto/thread/48cd3e88-d3a6-4943-b272-6d7ea81e11e3。當上面的異常出現時,我會看到下面的調用堆棧。

[email protected]() + 0x15 bytes 
[email protected]() + 0x15 bytes 
[email protected]() + 0x43 bytes  
[External Code] 


First-chance exception at 0x2ff2489e in Excel.exe: 0xC0000005: Access violation reading location 0x00000000. 
A first chance exception of type 'System.AccessViolationException' occurred in PublicCompModel.DLL 
An exception of type 'System.AccessViolationException' occurred in PublicCompModel.DLL but was not handled in user code 

不知道如果我濫用COM對象,但我肯定覺得很奇怪,我可以刪除所有表的複製本,並認爲這是本地到Excel。

回答

2

一個大量的調試,與微軟的VSTO團隊支持票,而一些漫長的夜晚之後,我終於得到了答案。問題不是源於我的代碼,而是源自工作簿本身。最初,我們將代碼編寫爲獨立項目,然後從用戶的電子表格模型中集成表單。關鍵問題是,當您開始複製其他工作簿中的工作表時,您將帶有對工作簿的命名參考。我們的用戶組向我們提供了一個文件,其中有數百個我們以前沒見過的不良引用。

即使你抑制警告Application對象,這些事件在後臺仍然射擊。在C#操作工作簿狀態時觸發的大量事件導致了AccessViolationException。

我學到的教訓:確保清理工作簿中並觀察該工作簿沒有你的代碼行爲。由於計時問題,我們被迫在Microsoft調試我們的代碼時重寫了VBA中的解決方案。在我們清理完資源之前,VBA代碼運行起來更加穩定,這可能源於它被解釋的事實,並且通過我的觀察,它運行在單個線程上。

順便說一句,如果你正在使用VSTO在文檔的環境中工作插件,你應該小心釋放引用。在很多情況下,您可能不需要這樣做,因爲Excel可能會爲您清理它。釋放COM對象被認爲是dangerous

+0

請將您的答案標記爲答案。 – Artemix

0

我記得有類似的東西。雖然我不記得具體細節,但這是我保存和關閉工作簿的模板。我希望這有助於某種方式。

xlWorkBook.SaveAs(fileName, Microsoft.Office.Interop.Excel.XlFileFormat.xlWorkbookNormal, misValue, misValue, misValue, misValue, Microsoft.Office.Interop.Excel.XlSaveAsAccessMode.xlExclusive, misValue, misValue, misValue, misValue, misValue); 
    xlWorkBook.Close(true, misValue, misValue); 
    xlApp.Quit(); 

    //Release objects 
    releaseObject(xlWorkSheet); 
    releaseObject(xlWorkBook); 
    releaseObject(xlApp); 

...

private void releaseObject(object obj) 
{ 
    try 
    { 
     System.Runtime.InteropServices.Marshal.ReleaseComObject(obj); 
     obj = null; 
    } 
    catch (Exception ex) 
    { 
     obj = null; 
     Response.Write("Exception Occured while releasing object " + ex.ToString()); 
    } 
    finally 
    { 
     GC.Collect(); 
    } 
} 
+0

感謝您的反饋,但我試圖以釋放內存時,我就可以了,我仍然有問題。我還看到的一個主要區別是我的代碼是用於文檔級定製的。我正在複製的工作簿是用戶正在與之交互的工作簿...還有一些我無法釋放的資源,因爲它們是在運行時實例化的全局主機項目的一部分。 – jaysqrd

+0

我還將我對FinalReleaseComObject的調用刪除,並改爲使用ReleaseComObject。 – jaysqrd

相關問題