none
Excel Add-in: GC.WaitForPendingFinalizers() hangs RRS feed

  • Question

  • The excel add-in project I'm working with spawns an excel process to generate charts based on a template. I then copy these charts into a word document, also based on a template. If I do this using:

    Excel.ChartObject chart = (Excel.ChartObject)charts.Item(1);
    chart.Select(true); //Exception from HRESULT: 0x800A03EC if this line isn't included     
    chart.Copy();
    
    Word.Range range = //(a bookmark in a word template)
    range.Paste();
    Everything works fine. However, if I use: 
    range.PasteAndFormat(Microsoft.Office.Interop.Word.WdRecoveryType.wdChart);

    instead of range.Paste(), my add-in hangs when I call  GC.WaitForPendingFinalizers() (as per this answer) at the end of my code. Eventually excel presents the message "Microsoft excel is waiting for another application to complete an OLE action."

    Why could this different paste method causeGC.WaitForPendingFinalizers() to hang?




    • Edited by ForeverWintr Monday, March 18, 2013 4:23 PM Formatting
    Monday, March 18, 2013 4:22 PM

Answers

  • deadlock on WaitForPendingFinalizers Means that you forgot to release something office related in your code. From Finalizer thread it tries to marshal back to your main thread where you are waiting for finalizer thread to finish so classical deadlock. Try to find out what object you forgot to call ReleaseComObject on. If you feel adventurous you could use windbg or visual studio with native debugging enabled to see what objects wait in finalizer queue.
    • Marked as answer by ForeverWintr Wednesday, March 20, 2013 3:53 PM
    • Unmarked as answer by ForeverWintr Wednesday, March 20, 2013 3:54 PM
    • Marked as answer by ForeverWintr Wednesday, March 20, 2013 3:54 PM
    Wednesday, March 20, 2013 6:27 AM

All replies

  • Hi ForeverWintr,

    You will need to follow the method 2 in the article to fix it.

    you should close excel application(you can call Quit method) before you call GC.WaitForPendingFinalizers().

    Thanks


    Tuesday, March 19, 2013 6:11 AM
  • Hi Learning hard,

    Thanks for the response. Unfortunately, quitting the app doesn't seem to change anything. Here's the code that runs as my add-in is finishing up:

    public void Quit()
    {
        object saveChanges = false;
    
        try
        {
            //see http://stackoverflow.com/a/159419/1286571
            //and http://www.xtremevbtalk.com/showthread.php?t=160433
    
            Marshal.FinalReleaseComObject(sheets);
            sheets = null;
    
            book.Close(saveChanges, GlobalVars.missing, GlobalVars.missing);
            Marshal.FinalReleaseComObject(book);
    
            books.Close();
            Marshal.FinalReleaseComObject(books);
    
            _app.Quit();
            Marshal.FinalReleaseComObject(_app);
            _app = null;
    
            GC.Collect();
            GC.WaitForPendingFinalizers(); //Hang here
            GC.Collect();
            GC.WaitForPendingFinalizers();
        }
        catch (Exception e)
        {
           Debug.Print("Error while trying to quit excelapp: " + e.Message + "\n\n" + e.ToString());
            throw e;
         }
    }
    Where _app is an instance of Excel.Application(). Regardless of whether I put the GC.WaitforPendingFinalizers() at the top or bottom of the try block, I get a hang on the first GC.WaitForPendingFinalizers(); 

    There are three Office instances at work in my application: 

    1) The excel process that the user interacts with (my add-in)

    2) The excel process that is spawned to generate charts

    3) The word process that the charts are copied into. 

    The excel app that I'm closing in code above is number 2. The other excel app is the one the user interacts with, and the word document is presented to the user, so neither of those can be closed by my code. 

    Tuesday, March 19, 2013 5:38 PM
  • I've just discovered that removing the following lines from my add-in's Startup method stops the hang:

    var excel = this.Application;
    WorkbookAdded(excel.ActiveWorkbook);
    ((Excel.AppEvents_Event)this.Application).NewWorkbook += WorkbookAdded;
    excel.WorkbookOpen += WorkbookAdded;
    excel.WorkbookActivate += WorkbookActivated;

    I've no idea why.

    Of course, now excel is disabling my application each time I start it up. 

    Tuesday, March 19, 2013 5:43 PM
  • deadlock on WaitForPendingFinalizers Means that you forgot to release something office related in your code. From Finalizer thread it tries to marshal back to your main thread where you are waiting for finalizer thread to finish so classical deadlock. Try to find out what object you forgot to call ReleaseComObject on. If you feel adventurous you could use windbg or visual studio with native debugging enabled to see what objects wait in finalizer queue.
    • Marked as answer by ForeverWintr Wednesday, March 20, 2013 3:53 PM
    • Unmarked as answer by ForeverWintr Wednesday, March 20, 2013 3:54 PM
    • Marked as answer by ForeverWintr Wednesday, March 20, 2013 3:54 PM
    Wednesday, March 20, 2013 6:27 AM
  • I think you're right. Apparently the lines I quoted above (which look like event handlers?) were causing the deadlock. 

    I had tried looking at the finalizer queue using native debugging in visual studio, but of course the deadlock did not occur when native debugging was enabled. I'm not sure why those lines would only cause a deadlock when I used 

    range.PasteAndFormat(Microsoft.Office.Interop.Word.WdRecoveryType.wdChart);

    either.

    Now I no longer experience hangs, but if I use PasteAndFormat instead of just Paste, my excel add-in gets disabled by excel. As far as I can tell no exceptions are thrown by my code; can anyone offer insight into why excel decides to disable my add-in?

    P.S. These forums are absolutely terrible... I made the mistake of marking DamianD's post as an answer as I was half way through writing this response, and the forums deleted everything I'd written. 


    Wednesday, March 20, 2013 4:03 PM
  • if you do not feel like debugging your code, you could try to move call to GC.WaitForPendingFinalizers to separate thread and do not wait for it, it should free your main thread to accept Marshall calls from finalizer queue (of course it does not mean that some exception will not be thrown)
    Thursday, March 21, 2013 8:54 AM