0

UPDATED: added full block of code where error occurs

UPDATE 2: I found a weird anomaly. The code has now been continuously breaking on that line, when the tabName variable equals "service line prior year". This morning, for grins, I changed the tab name to "test", so in turn the tabName variable equals "test", and it worked more often then not. I am really at a loss.

I have researched a ton and can't find anything that addresses what is happening in my code. It happens randomly though. Sometimes it doesn't happen, then other times it happens in the same spot, but all on this part of the code (on the line 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();
            }

    }

The try/catch block is of no use either. This is the error:

"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."
Darw1n34
  • 312
  • 7
  • 24
  • Sorry, but you need to elaborate more your question. Place the relevant code and information organised, try to see the inner exception and tell us what have you been trying to achieve... – gustavodidomenico Jul 10 '15 at 20:15
  • @gustavodidomenico I have added the entire block in which the error occur when/if it occurs. I am thinking at this point maybe its a memory buffer issue. – Darw1n34 Jul 10 '15 at 20:36

2 Answers2

0

System.AccessViolationException would normally happen when you try to access an unallocated memory in a native code (not .NET). Then .NET translates it to the managed world as this exception.

Your code itself does not have any unsafe block. So access violation must me happening inside Excel.

Given the fact that it sometimes happens, some times not, I would say that it can be caused by a parallel Excel usage (I think the Excel COM is not thread-safe).

I would recommend you putting all your code inside a lock block, to prevent Excel from begin used in parallel. Something like this:

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
    }
}
ecsousa
  • 158
  • 6
  • Thanks, I tried this but first run, it threw the same exception. I will keep digging with the parallel excel in mind. – Darw1n34 Jul 13 '15 at 14:39
0

So long story, three days of testing longer, it was because of an excel file that was trying to open and fill with SQL results. The buffer was filling up and causing an exception...it just happened at the same point in every run because the load time for the excel file was the determining factor in it working or failing.

So after the load i just added a delaying do...while that checked to see if the file was accessible or not and it stopped the failures. fileOpenTest was taken from here

           do
            {
                Task.Delay(2000);
            } 
            while(!fileOpenTest);
Community
  • 1
  • 1
Darw1n34
  • 312
  • 7
  • 24