我正在做一个项目,我需要在 Excel 中自动化一些工作流程,但我遇到了一个非常讨厌的障碍。在项目中,我使用 Visual Studio Tools For Office 创建文档级加载项。用户使用作为该项目一部分的功能区控件来自动从项目外部的工作簿复制工作表。外部工作簿从 SQL blob 加载并写入磁盘。加载项代码打开每个工作簿,将工作表复制到加载项工作簿中,然后关闭该外部工作簿。通常,第一个工作簿可以正常工作,但打开后续工作簿将引发 AccessViolationException。
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。当出现上述异常时,我看到以下调用堆栈。
ntdll.dll!_ZwWaitForSingleObject@12() + 0x15 bytes
ntdll.dll!_ZwWaitForSingleObject@12() + 0x15 bytes
kernel32.dll!_WaitForSingleObjectExImplementation@12() + 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 本地的。