locked
COMException 800ac472 on a VSTA_MAIN? RRS feed

  • Question

  • I have a Workbook app, VSTO 2005, Excel 2003 and I am getting the said COMException on a call to Application.StatusBar = "SomeText".

    I checked the thread and it is VSTA_MAIN, so I assumed that if Excel was busy that the call would simply be ignored.  I searched for the error on google and came across this post by Andrew Whitechapel:

    http://blogs.msdn.com/andreww/archive/2008/11/19/implementing-imessagefilter-in-an-office-add-in.aspx

    If you don’t create any background threads in your add-in, and therefore make all OM calls on the same thread your add-in was created on, your call won’t fail, it simply won’t be invoked until the host is unblocked. Then, it will be processed in sequence. This is the normal case, and it is recommended that this is how you design your Office solutions in most scenarios – that is, without creating any new threads.

    However, if you do create additional threads, and attempt to make OM calls on any of those threads, then the calls will simply fail if the host is blocked. You’ll get a COMException, typically something like this: System.Runtime.InteropServices.COMException, Exception from HRESULT: 0x800AC472.

    It seems although he's referring to an Addin solution, that a call into Excel object model will only fail if you try to call into Excel on different threads.  And then he goes onto the IMessageFilter solution, which I also saw in one other post in this forum.

    Can someone shed some light into this issue?

    Thanks
    Jiho

    Tuesday, January 27, 2009 5:49 PM

Answers

  • Hi there,

    just for fun:

    public partial class ThisWorkbook  
    {  
     
        private System.Timers.Timer _updateTimer;  
        private BackgroundWorker _worker;  
     
        private void ThisWorkbook_Startup(object sender, System.EventArgs e)  
        {  
            _updateTimer = new System.Timers.Timer(100);  
            _updateTimer.AutoReset = true;   
            _updateTimer.Elapsed += new System.Timers.ElapsedEventHandler(_updateTimer_Elapsed);  
            _updateTimer.Enabled  = true;   
     
            _worker = new BackgroundWorker();  
            _worker.DoWork += new DoWorkEventHandler(_worker_DoWork);  
            _worker.RunWorkerAsync();   
        }  
     
        void _updateTimer_Elapsed(object sender, System.Timers.ElapsedEventArgs e) {  
            UpdateStatusBar();  
        }  
     
        void _worker_DoWork(object sender, DoWorkEventArgs e) {  
            for (int i = 1; i < 1000; i++) {  
                Thread.Sleep(1000);  
                MyGlobals.StatusMessage = string.Format("Step: {0}", i);   
            }  
        }  
     
        private void ThisWorkbook_Shutdown(object sender, System.EventArgs e)  
        {  
        }  
     
        private void UpdateStatusBar() {  
            string message = MyGlobals.StatusMessage;  
            Globals.ThisWorkbook.Application.StatusBar = message;    
        }
        #region VSTO Designer generated code  
     
        /// <summary>  
        /// Required method for Designer support - do not modify  
        /// the contents of this method with the code editor.  
        /// </summary>  
        private void InternalStartup()  
        {  
            this.Startup += new System.EventHandler(ThisWorkbook_Startup);  
            this.Shutdown += new System.EventHandler(ThisWorkbook_Shutdown);  
        }
        #endregion  
     

    basically it is working except:

    When you click with the Mouse in the Excel Window, then you get the Exception, because Excel can't process your request.
    In my case I simply ignore this Exception. The next Timer event will try to update the StatusBar.

    private void UpdateStatusBar() {  
        string message = MyGlobals.StatusMessage;  
        try {  
            Globals.ThisWorkbook.Application.StatusBar = message;  
        } catch (COMException ex) {  
            // Excel is busy...  
            if (ex.ErrorCode != -2146777998)  
            {  
                throw;  
            }  
        }  

    Just a proof of Concept

    greets - Helmut

     


    Helmut Obertanner [http://www.x4u.de] [http://www.outlooksharp.de]
    Tuesday, January 27, 2009 10:14 PM
    Answerer

All replies

  • Hello doughboy -

    If you don't access this Property from a second thread in your AddIn,
    how exactly are you setting this Property?

     

    The MSDN Documentation says:

    http://msdn.microsoft.com/en-us/library/microsoft.office.interop.excel._application.statusbar(VS.80).aspx

    Remarks

    This property returns False if Microsoft Excel has control of the status bar. To restore the default status bar text, set the property to False; this works even if the status bar is hidden.


    Any public static (Shared in Visual Basic) members of this type are thread safe. Any instance members are not guaranteed to be thread safe.

    Helmut Obertanner [http://www.x4u.de] [http://www.outlooksharp.de]
    Tuesday, January 27, 2009 7:52 PM
    Answerer
  •  I'm not certain I understand what you mean by second thread.  My app is not an addin but a workbook, not sure whether that makes any difference.  I am setting the the StatuBar on the thread named VSTA_Main, this is the same thread that comes in on Startup and Open events of the workbook, and is the same thread that comes in on when you click on a button on the ActionsPane.

    Also, can you clarify what you are trying to say regarding the MSDN documentation?

    Globals, if you mean the friend class that gets setup in ThisWorkbook designer file, then it only contains the same workbook instance - Microsoft.Office.Tools.Excel.Workbook.  Not sure where you're going with this...

    Thanks

    Jiho

    Tuesday, January 27, 2009 9:15 PM
  • Hello doughboy,

    Just created a small Workbook and added this code into the Startup Method.

    this works fine for me:

     

    private void ThisWorkbook_Startup(object sender, System.EventArgs e)  
    {  
        Globals.ThisWorkbook.Application.StatusBar = "Hello World...";   

    The Text "Hello World..." is in the Status Bar after opening the Workbook.

    Greets - Helmut


    Helmut Obertanner [http://www.x4u.de] [http://www.outlooksharp.de]
    Tuesday, January 27, 2009 9:22 PM
    Answerer
  • Yes, that works ok for me too.  Most of the time.

    It fails on occasions and throws COMException and then the thread dies.  That's the question: why does it work fine, then fail at other times?

    Like I said, all updates to the StatusBar is being invoked from the original thread - I do have worker threads but when calling StatusBar, I do marshall the call back to VSTA_Main.

    Tuesday, January 27, 2009 9:26 PM
  • Hi,

    then I'm out of luck here.
    Try to post at Andrews Blog.

    Maybe he can help you - I'm not so deep in COM Interop.
    Maybe you can use a Workaround.

    Use a Timer, that checks for a Variable, read it an set the StatusBar.
    Avoid deadlocks using the lock() macro.

    This is how I would try to resolve this.

     

    Greets - Helmut

     

     


    Helmut Obertanner [http://www.x4u.de] [http://www.outlooksharp.de]
    Tuesday, January 27, 2009 9:44 PM
    Answerer
  • Thanks for your help though.

    So, you don't see a way to see whether Excel is "busy", do you?  Other than catch the COMException...

    Anyway, FYI, I created a sample app that can demonstrate what I mean.  When you click on the button after starting the progress bar, you should get the COMException.

    But I don't see an attach file functionality on this forum...

    Tuesday, January 27, 2009 10:08 PM
  • Hi there,

    just for fun:

    public partial class ThisWorkbook  
    {  
     
        private System.Timers.Timer _updateTimer;  
        private BackgroundWorker _worker;  
     
        private void ThisWorkbook_Startup(object sender, System.EventArgs e)  
        {  
            _updateTimer = new System.Timers.Timer(100);  
            _updateTimer.AutoReset = true;   
            _updateTimer.Elapsed += new System.Timers.ElapsedEventHandler(_updateTimer_Elapsed);  
            _updateTimer.Enabled  = true;   
     
            _worker = new BackgroundWorker();  
            _worker.DoWork += new DoWorkEventHandler(_worker_DoWork);  
            _worker.RunWorkerAsync();   
        }  
     
        void _updateTimer_Elapsed(object sender, System.Timers.ElapsedEventArgs e) {  
            UpdateStatusBar();  
        }  
     
        void _worker_DoWork(object sender, DoWorkEventArgs e) {  
            for (int i = 1; i < 1000; i++) {  
                Thread.Sleep(1000);  
                MyGlobals.StatusMessage = string.Format("Step: {0}", i);   
            }  
        }  
     
        private void ThisWorkbook_Shutdown(object sender, System.EventArgs e)  
        {  
        }  
     
        private void UpdateStatusBar() {  
            string message = MyGlobals.StatusMessage;  
            Globals.ThisWorkbook.Application.StatusBar = message;    
        }
        #region VSTO Designer generated code  
     
        /// <summary>  
        /// Required method for Designer support - do not modify  
        /// the contents of this method with the code editor.  
        /// </summary>  
        private void InternalStartup()  
        {  
            this.Startup += new System.EventHandler(ThisWorkbook_Startup);  
            this.Shutdown += new System.EventHandler(ThisWorkbook_Shutdown);  
        }
        #endregion  
     

    basically it is working except:

    When you click with the Mouse in the Excel Window, then you get the Exception, because Excel can't process your request.
    In my case I simply ignore this Exception. The next Timer event will try to update the StatusBar.

    private void UpdateStatusBar() {  
        string message = MyGlobals.StatusMessage;  
        try {  
            Globals.ThisWorkbook.Application.StatusBar = message;  
        } catch (COMException ex) {  
            // Excel is busy...  
            if (ex.ErrorCode != -2146777998)  
            {  
                throw;  
            }  
        }  

    Just a proof of Concept

    greets - Helmut

     


    Helmut Obertanner [http://www.x4u.de] [http://www.outlooksharp.de]
    Tuesday, January 27, 2009 10:14 PM
    Answerer
  • Thanks for that bit of code.

    If it were just StatusBar then that solution would be adequate but in our app, we happen to touch a lot more properties.  So it'll be another project for me to search out those places where excel is being touched while it's busy and put a bandage on it.

    I was just surprised at the COMException as I thought on VSTA_Main, we were fine but apparently we're not.  Perhaps it was just my misunderstanding all along.

    Thanks again!

    Jiho

    Tuesday, January 27, 2009 10:32 PM