0

So I have created this program and it should reset the value and type of the cell to 1 and integer on startup. Then when the user wants to add a name, it should read the value and set it as AmountNumD (because it seems to detect it as a double). The program then converts this into an integer AmountNum and uses this in a number of ways leading to the creation of a textbox, progress bar and checkbox on the main form. This works, except when you go to the add name page again, it crashes giving the error: Exception from HRESULT: 0x800401A8.

Below are extracts from my code:

Resetting Cells:

if (File.Exists(StudentDirectory) == true)
        {
            Excel.Application ExcelOApp;
            Excel.Worksheet ExcelOSheet;
            Excel.Workbook ExcelOBook;

            ExcelOApp = new Excel.Application();
            ExcelOBook = ExcelOApp.Workbooks.Open(StudentDirectory);
            ExcelOSheet = (Excel.Worksheet)ExcelOBook.Worksheets.get_Item(1);


            ExcelOSheet.Cells[1, 8] = "Amount Number";
            //deleting old content for Constant Number
            //Excel.Range rngCon = ExcelOSheet.get_Range(2, 8);
            var rngCon = ExcelOSheet.Cells[2, 8];
            rngCon.Cells.NumberFormat = "0";
            rngCon.Cells.Value = "1";

            ExcelOBook.SaveAs(StudentDirectory);
            ExcelOBook.Close();
            ExcelOApp.Quit();
        }
        else
        {
            CreateStudentWorksheet();
            //Goes to a similar section that creates new excel file
        }

Adding students (Note this is on a separate form):

public static string StudentDirectory = "C:\\Users\\Administrator\\Desktop\\Prototype5\\Save Folder\\Students.xlsx";
    //Creating Variables that link to the Student Data Excel File
    public static Excel.Application ExcelApp = new Excel.Application();
    public static Excel.Workbook ExcelBook = ExcelApp.Workbooks.Open(StudentDirectory, 0, false, 5, "", "", true, Excel.XlPlatform.xlWindows, "\t", true, false, 1, 0);
    public static Excel._Worksheet ExcelSheet = (Excel._Worksheet)ExcelBook.Sheets[1];
    //public static ExcelApp.DisplayAlerts = false;

    //Creating a constant number so that the form knows where to put student assets
    int AmountNum;
    double AmountNumD = ExcelSheet.Cells[2, 8].Value;


    public void Constant()
    {
        ExcelApp.DisplayAlerts = false;
        AmountNum = Convert.ToInt32(AmountNumD);
        AmountNum = AmountNum + 1;
        double AmountNumDTwo = Convert.ToDouble(AmountNum);
        ExcelSheet.Cells[2, 8].Value = AmountNumDTwo;
        WritingToExcel(AmountNum);
    }

    private void WritingToExcel(int AmountNum)
    {
        string StudentName = NameBox.Text;
        string StudentPassword = PasswordBox.Text;
        ExcelSheet.Cells[AmountNum, 1].Value = StudentName;
        ExcelSheet.Cells[AmountNum, 5].Value = StudentPassword;
    }

    private void SaveButton_Click(object sender, EventArgs e)
    {
        Constant();
        ExcelBook.Save();
        ExcelApp.Quit();
        this.Close();

    }

What happens in the main form after student details are entered and a button calling this function is pressed:

Excel.Application ExcelApp = new Excel.Application();
        Excel.Workbook ExcelBook = ExcelApp.Workbooks.Open(StudentDirectory, 0, true, 5, "", "", true, Excel.XlPlatform.xlWindows, "\t", true, false, 1, 0);
        Excel._Worksheet ExcelSheet = (Excel._Worksheet)ExcelBook.Sheets[1];
        //Excel.Range NamesRng = ExcelSheet.Cells["A2", "A35"];

        int StartColumn = 138;
        int StartRow = 72;
        int AmountNum;
        double AmountNumD = ExcelSheet.Cells[2, 8].Value;
        AmountNum = Convert.ToInt32(AmountNumD);


        if (AmountNum == 1)
        {
            MessageBox.Show("Please Enter a student first");
        }
        if (AmountNum == 2)
        {
            TextBox TB2 = new TextBox();
            TB2.Name = ("Name" + (AmountNum));
            TB2.Location = new Point(StartColumn, StartRow);
            TB2.Size = new Size(78, 22);
            TB2.ReadOnly = true;
            TB2.Text = ExcelSheet.Cells[AmountNum, 1].Text;
            this.Controls.Add(TB2);
            TB2.BringToFront();
            TB2.Show();
            ProgressBar PB2 = new ProgressBar();
            PB2.Name = ("ProgressBar" + (AmountNum));
            PB2.Location = new Point(StartColumn + 87, StartRow);
            PB2.Size = new Size(447, 23);
            this.Controls.Add(PB2);
            PB2.BringToFront();
            PB2.Show();
            CheckBox CB2 = new CheckBox();
            CB2.Name = ("CheckBox" + (AmountNum));
            CB2.Location = new Point(StartColumn + 550, StartRow);
            CB2.Size = new Size(23, 23);
            this.Controls.Add(CB2);
            CB2.BringToFront();
            CB2.Show();
        }
        if (AmountNum == 3)
        {
            StartLoc = StartLoc + 1;

            //28px between each student
            StartRow = StartRow + (StartLoc * 28);
            TextBox TB = new TextBox();
            TB.Name = ("Name" + (AmountNum));
            TB.Location = new Point(StartColumn, StartRow);
            TB.Size = new Size(78, 22);
            TB.ReadOnly = true;
            TB.Text = ExcelSheet.Cells[AmountNum, 1].Text;
            this.Controls.Add(TB);
            TB.BringToFront();
            //TB.Show();
            ProgressBar PB = new ProgressBar();
            PB.Name = ("ProgressBar" + (AmountNum));
            PB.Location = new Point(StartColumn + 87, StartRow);
            PB.Size = new Size(447, 23);
            this.Controls.Add(PB);
            PB.BringToFront();
            //PB.Show();
            CheckBox CB = new CheckBox();
            CB.Name = ("CheckBox" + (AmountNum));
            CB.Location = new Point(StartColumn + 550, StartRow);
            CB.Size = new Size(23, 23);
            this.Controls.Add(CB);
            CB.BringToFront();
            //CB.Show();
         }
//The program carries on like this for all 35 potential students

Thank you in advance.

Jonathan Bravetti
  • 2,228
  • 2
  • 15
  • 29
pcconfuser
  • 25
  • 5
  • Which line is throwing the exception? If you search for "HRESULT: 0x800401A8" there are lots of results about Excel interop, it's apparently the equivalent of a "null reference exception". You are opening Excel in a class field initializer and closing it in a save button in one spot and opening/closing it also in another spot. Maybe you are trying to access an object from an already-closed instance of excel. Also separately I don't think you are cleaning up your COM objects properly. If you aren't then you will have a bunch of zombie Excel exe's running still which you can see in task manager. – Quantic Oct 06 '16 at 15:38
  • The exception is being thrown here : double AmountNumD = ExcelSheet.Cells[2, 8].Value; That explains why I have to keep going into task manager and removing Excel.exe files. How would I go about cleaning up my COM objects? – pcconfuser Oct 07 '16 at 08:03
  • I seem to have solved the closing of the COM objects after use by removing a few of the unneeded ExcelApp.Quit() and adding Marshal.ReleaseComObject(ExcelSheet); This then lead me to get a new error message, but at the same spot as before. I did my research and I am still not quite understanding what is wrong. The error message is as follows: "COM object that has been separated from its underlying RCW cannot be used." – pcconfuser Oct 10 '16 at 14:14
  • You have two lines that show `double AmountNumD = ExcelSheet.Cells[2, 8].Value`, which one of the two is throwing? My gut feels like using static field initialization to open Excel is the problem. I think you should try moving all of these lines: `public static Excel.Application ExcelApp = new Excel.Application();` to an `OpenButton_Click()`, so you click `Open` which opens excel in a non-static way, then eventually you click `Save` which closes it; don't rely on the static initializers. And I would just open it once then enter all the students too, don't open and close it each time. – Quantic Oct 10 '16 at 15:37
  • As for COM cleanup [this post](http://stackoverflow.com/a/158752/5095502) was helpful for me. You need to com release the app, the workbook, the worksheets, the worksheet, and I'm pretty sure the range object created by the `ExcelOSheet.Cells` call as well. Pretty sure you can't do `Excel._Worksheet ExcelSheet = (Excel._Worksheet)ExcelBook.Sheets[1];`, I think this creates `Worksheets` object that you have no reference for to clean up. You need to do `var workSheets = (Excel._Worksheet)ExcelBook.Sheets`, `var thisSheet = workSheets[1]`, then you can clean both objects up. – Quantic Oct 10 '16 at 15:48
  • It is the line of code in the adding students section. I tried doing the adding all students in one go and saving it each time by adding some more code, but It seems to only create the dynamic controls for the last student I added. – pcconfuser Oct 11 '16 at 11:55

0 Answers0