发生'System.AccessViolationException'

时间:2015-07-10 20:10:13

标签: c#

更新:添加了发生错误的完整代码块

更新2:我发现了一个奇怪的异常现象。当tabName变量等于“上一年的服务线”时,代码现在一直在该行上断开。今天早上,对于笑脸,我将标签名称更改为“test”,因此tabName变量等于“test”,并且它更频繁地工作,然后没有。我真的很茫然。

我研究了很多,找不到任何可以解决我的代码中发生的事情的东西。它虽然随机发生。有时它不会发生,然后有时会发生在同一个地方,但所有这些都在代码的这一部分上(在行templateSheet = templateBook.Sheets [tabName];):

 public void ExportToExcel(DataSet dataSet, string filePath, int i, int h, Excel.Application excelApp)
    {
            //create the excel definitions again.
            //Excel.Application excelApp = new Excel.Application();
            //excelApp.Visible = true;
            FileInfo excelFileInfo = new FileInfo(filePath);
            Boolean fileOpenTest = IsFileOpen(excelFileInfo);

            Excel.Workbook templateBook;
            Excel.Worksheet templateSheet;

            //check to see if the template is already open, if its not then open it,
            //if it is then bind it to work with it
            if (!fileOpenTest)
            { templateBook = excelApp.Workbooks.Open(filePath); }
            else
            { templateBook = (Excel.Workbook)System.Runtime.InteropServices.Marshal.BindToMoniker(filePath); }


            //this grabs the name of the tab to dump the data into from the "Query Dumps" Tab
                string tabName = lstQueryDumpSheet.Items[i].ToString();

                templateSheet = templateBook.Sheets[tabName];
                excelApp.Calculation = Excel.XlCalculation.xlCalculationManual;

                templateSheet = templateBook.Sheets[tabName];        

            // Copy DataTable
            foreach (System.Data.DataTable dt in dataSet.Tables)
            {
                // Copy the DataTable to an object array
                object[,] rawData = new object[dt.Rows.Count + 1, dt.Columns.Count];

                // Copy the values to the object array
                for (int col = 0; col < dt.Columns.Count; col++)
                {
                    for (int row = 0; row < dt.Rows.Count; row++)
                    { rawData[row, col] = dt.Rows[row].ItemArray[col]; }
                }

                // Calculate the final column letter
                string finalColLetter = string.Empty;
                string colCharset = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
                int colCharsetLen = colCharset.Length;

                if (dt.Columns.Count > colCharsetLen)
                { finalColLetter = colCharset.Substring((dt.Columns.Count - 1) / colCharsetLen - 1, 1); }

                finalColLetter += colCharset.Substring((dt.Columns.Count - 1) % colCharsetLen, 1);

                //this grabs the cell address from the "Query Dump" sheet, splits it on the '=' and
                //pulls out only the cell address (i.e., "address=a3" becomes "a3")
                string dumpCellString = lstQueryDumpText.Items[i].ToString();
                string dumpCell = dumpCellString.Split('=').Last();

                //referts to the range in which we are dumping the DataSet.  The upper right hand cell is
                //defined by the 'dumpCell' varaible and the bottom right cell is defined by the 
                //final column letter and the count of rows.
                string firstRef = "";
                string baseRow = "";

                if (char.IsLetter(dumpCell, 1))
                {
                    char[] createCellRef = dumpCell.ToCharArray();
                    firstRef = createCellRef[0].ToString() + createCellRef[1].ToString();
                    for (int z = 2; z < createCellRef.Count(); z++)
                    {
                        baseRow = baseRow + createCellRef[z].ToString();
                    }
                }
                else
                {
                    char[] createCellRef = dumpCell.ToCharArray();
                    firstRef = createCellRef[0].ToString();
                    for (int z = 1; z < createCellRef.Count(); z++)
                    {
                        baseRow = baseRow + createCellRef[z].ToString();
                    }
                }

                int baseRowInt = Convert.ToInt32(baseRow);
                int startingCol = ColumnLetterToColumnIndex(firstRef);
                int endingCol = ColumnLetterToColumnIndex(finalColLetter);

                int finalCol = startingCol + endingCol;
                string endCol = ColumnIndexToColumnLetter(finalCol - 1);
                int endRow = (baseRowInt + (dt.Rows.Count - 1));
                string cellCheck = endCol + endRow;
                string excelRange;

                if (dumpCell.ToUpper() == cellCheck.ToUpper())
                {
                    excelRange = string.Format(dumpCell + ":" + dumpCell);
                }
                else
                {
                    excelRange = string.Format(dumpCell + ":{0}{1}", endCol, endRow);
                }

                //this dumps the cells into the range on Excel as defined above
                templateSheet.get_Range(excelRange, Type.Missing).Value2 = rawData;

                //checks to see if all the SQL queries have been run from the "Query Dump" tab, if not, continue 
                //the loop, if it is the last one, then save the workbook and move on.

                if (i == lstSqlAddress.Items.Count - 1)
                {
                    excelApp.Calculation = Excel.XlCalculation.xlCalculationAutomatic;

                    /*Run through the value save sheet array then grab the address from the corresponding list 
                    place in the address array.  If the address reads "whole sheet" then save the whole page,
                    else set the addresses range and value save that.*/
                    //for (int y = 0; y < lstSaveSheet.Items.Count; y++)
                    //{
                    //    MessageBox.Show("Save Sheet: " + lstSaveSheet.Items[y] + "\n" + "Save Address: " + lstSaveRange.Items[y]);
                    //}

                    //run the macro to hide the unused columns
                    excelApp.Run("ReportMakerExecute");

                    //save excel file as hospital name and move onto the next
                    SaveTemplateAs(templateBook, h);

                    //close the open Excel App before looping back
                    //Marshal.ReleaseComObject(templateSheet);
                    //Marshal.ReleaseComObject(templateBook);
                    //templateSheet = null;
                    //templateBook = null;
                    //GC.Collect();
                    //GC.WaitForPendingFinalizers();
                }
                //Close excel Applications
                //excelApp.Quit();
                //Marshal.ReleaseComObject(templateSheet);
                //Marshal.FinalReleaseComObject(excelApp);
                //excelApp = null;
                //templateSheet = null;
                // GC.Collect();
                //GC.WaitForPendingFinalizers();
            }

    }

try / catch块也没用。这是错误:

"An unhandled exception of type 'System.AccessViolationException' occurred inSQUiRE (Sql QUery REtriever) v1.exe.  Additional information: Attempted to read or write protected memory. This is often an indication that other memory is corrupt."

1 个答案:

答案 0 :(得分:0)

当您尝试访问本机代码(而不是.NET)中的未分配内存时,通常会发生

System.AccessViolationException。然后,.NET将其转换为托管世界,作为此异常。

您的代码本身没有任何不安全的阻止。因此,访问冲突必须发生在Excel内部。

鉴于它有时会发生,有时不会发生,我会说它可能是由并行Excel使用引起的(我认为Excel COM不是线程安全的)。

我建议您将所有代码放在lock块中,以防止Excel开始并行使用。像这样:

public void ExportToExcel(DataSet dataSet, string filePath, int i, int h, Excel.Application excelApp)
{
    lock(this.GetType()) // You can change here to other instance to me used a mutex
    {
        // Your original code here
    }
}