2

Everytime I run this code, the object won't close. I still have an excel.exe running in the task manager. Even if I set the objects = null, still nothing. I've even tried using the objects .Quit() method.

What am I doing wrong here?

    private bool ValidateQM()
    {
        //setup the objects
        Excel.Application oXL = null;
        Excel.Workbook oWB = null;
        Excel.Worksheet oSheet = null;
        int hWnd = 0;

        try
        {

            //Start Excel and get Application object.
            oXL = new Excel.Application();
            hWnd = oXL.Application.Hwnd;
            oXL.Visible = false;

            //Open the workbook.
            oWB = oXL.Workbooks.Open(workingForm, 0, false, 5, "", "", false, Excel.XlPlatform.xlWindows, "",true, false, 0, true, false, false);

            //Get the Worksheet
            oSheet = oWB.Worksheets[1];

            //Check the date values

            string mydatetime = oSheet.Cells[5, 33].Text.ToString() + " " + oSheet.Cells[7, 33].Text.ToString();
            string dateofscore = oSheet.Cells[3, 12].Text.ToString();

            DateTime.Parse(mydatetime); //make my string a real boy
            DateTime.Parse(dateofscore);

            // Cleanup 
            GC.Collect();
            GC.WaitForPendingFinalizers();

            System.Runtime.InteropServices.Marshal.FinalReleaseComObject(oSheet);

            //oWB.Close();
            System.Runtime.InteropServices.Marshal.FinalReleaseComObject(oWB);

            //oXL.Quit();
            System.Runtime.InteropServices.Marshal.FinalReleaseComObject(oXL);

            return true;
        }
Mark Kram
  • 5,672
  • 7
  • 51
  • 70
CodingIsAwesome
  • 1,946
  • 7
  • 36
  • 54
  • 2
    The code is unholy, mixing both automatic and manual memory management and ending up with neither. But it doesn't work because you are debugging the Debug build. There are hidden object references generated by the Cells[,] indexers. They keep Excel alive until the end of the method when you are debugging. It will work in the Release build without a debugger. Move the bulk of the code in a separate method to improve the outcome. – Hans Passant Mar 03 '12 at 12:08

3 Answers3

1

When you call GC.Collect(), the oXL and oWB objects are still in scope so there's a reference active to them. As a result, GC.Collect() won't touch them. If you want to ensure they are garbage collected, set them to null so there's no references active when GC.Collect() is called. Also, you may want to call Close() on the active workbook and Quit() on the Excel application. You could also put everything in its own scope with braces { } so that it all went out of scope together.

        // Cleanup 
        oWB.Close(false);
        oWB = null;
        oXL.Quit();
        oXL = null;
        hWnd = null;
#if (DEBUG_SPEED_UP_GC)
        GC.Collect();
        GC.WaitForPendingFinalizers();
#endif

Edit: Note that manually calling garbage collection is a bad idea. I am assuming you are only doing this for debugging purposes to speed up when the GC occurs, so I added the #if.

Ed Bayiates
  • 11,060
  • 4
  • 43
  • 62
  • 2
    Or better yet, don't manually invoke garbage collection, preventing a slew of intractable bugs. – Cody Gray - on strike Mar 02 '12 at 22:38
  • @Cody, I had assumed he was only invoking garbage collection for debugging purposes. Agree it would be bad for both bugs and performance reasons to do this in a live application. – Ed Bayiates Mar 05 '12 at 18:26
  • There are not very many good reasons to invoke garbage collection for debugging purposes, considering you won't ever be doing it otherwise. In fact, I can't think of any (but as soon as I say none, someone will come up with some obscure edge case in response). The point is, this doesn't really solve this problem. Also, your answer doesn't make clear that you really *shouldn't* be doing this, which I think is a mistake. – Cody Gray - on strike Mar 05 '12 at 18:29
1

Aren't you falling foul of the "don't use 2 dots" rule in the line hWnd = oXL.Application.Hwnd ? See Excel interop libraries incompatible with ASP.NET? for more on this.

Community
  • 1
  • 1
Akash
  • 2,311
  • 1
  • 20
  • 37
0

I'm going to assume that an exception is not thrown and the catch handler that you're not showing doesn't do anything malign for the purposes of your problem.

I've even tried using the object's Quit method

Unless there's some documented advice against this, I don't see why you wouldn't always call Quit to indicate you have finished with the application.

//Start Excel and get Application object. oXL = new
Excel.Application();
hWnd = oXL.Application.Hwnd;
oXL.Visible = false;

Nevermind that you're changing the visibility of a window you don't own, what happens if Excel displays a warning while quitting? Setting Visible to false on the parent window will obscure it from the user.

For the purposes of debugging, try not hiding the window.

There's some information here on what you can do to prevent Excel from producing warnings that would otherwise require interactive attention. The basic gist of it:

DisplayAlerts = false
AskToUpdateLinks = false
AlertBeforeOverwriting = false
Interactive = false
Visible = false
FeatureInstall = 0 'msoFeatureInstallNone

You are running your application inside an interactive user session, right? Because anything else is not supported:

Microsoft does not currently recommend, and does not support, Automation of Microsoft Office applications from any unattended, non-interactive client application or component (including ASP, ASP.NET, DCOM, and NT Services), because Office may exhibit unstable behavior and/or deadlock when Office is run in this environment.

Community
  • 1
  • 1
ta.speot.is
  • 26,914
  • 8
  • 68
  • 96