Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I avoid RPC_E_CALL_REJECTED exceptions when performing PowerPoint automation?

When my code tries to create a new instance of Microsoft.Office.Interop.PowerPoint.Application, I sometimes get the following exception:

System.Runtime.InteropServices.COMException (0x80010001): Retrieving the COM class factory for component with CLSID {91493441-5A91-11CF-8700-00AA0060263B} failed due to the following error: 80010001 Call was rejected by callee. (Exception from HRESULT: 0x80010001 (RPC_E_CALL_REJECTED)).
   at System.Runtime.Remoting.RemotingServices.AllocateUninitializedObject(RuntimeType objectType)
   at System.Runtime.Remoting.Activation.ActivationServices.CreateInstance(RuntimeType serverType)
   at System.Runtime.Remoting.Activation.ActivationServices.IsCurrentContextOK(RuntimeType serverType, Object[] props, Boolean bNewObj)
   at System.RuntimeTypeHandle.CreateInstance(RuntimeType type, Boolean publicOnly, Boolean noCheck, Boolean& canBeCached, RuntimeMethodHandleInternal& ctor, Boolean& bNeedSecurityCheck)
   at System.RuntimeType.CreateInstanceSlow(Boolean publicOnly, Boolean skipCheckThis, Boolean fillCache)
   at System.RuntimeType.CreateInstanceDefaultCtor(Boolean publicOnly, Boolean skipVisibilityChecks, Boolean skipCheckThis, Boolean fillCache)
   at System.Activator.CreateInstance(Type type, Boolean nonPublic)

I say sometimes because it doesn't happen consistently even given the same input. Furthermore, it also occurs (with the same lack of consistency) in other parts of my code where I also interact with the PowerPoint automation API.

I have tried out this solution from MSDN itself which seems to be the most recommended solution out there. However, it doesn't seem to have any impact as I still observe the same behavior.

My questions are:

  1. Does the MSDN solution work for PowerPoint automation?
  2. How can I verify whether I have correctly applied it to my code?
  3. Does anyone have an alternative solution?

I am using C#, .NET 4, and PowerPoint 2007.

like image 608
Chry Cheng Avatar asked Sep 05 '12 11:09

Chry Cheng


2 Answers

I have run into this before and Paul B is indeed correct. It depends on whether you are calling the Powerpoint OM from the main thread (i.e. This_AddIn) or not. If you are, ppt should not throw these exceptions. However, if you are calling ppt from another thread, you must implement IMessageFilter to handle these windows message pump errors efficiently since ppt prioritizes main thread calls to the OM over calls from other threads, hence the call rejections.

There is another caveat that requires further boiler plate code to handle additional COMExceptions such as 0x800AC472 (VBA_E_IGNORE). There is an example here.

So, the full solution is both to implement IMessageFilter and to use something like sepp2k's code in which to wrap your OM calls in order to handle other types of COMException that may be thrown.

So, for wrapping code like his:

private void TryUntilSuccess(Action action)
{
    bool success = false;
    while (!success)
    {
        try
        {
            action();
            success = true;
        }

        catch (System.Runtime.InteropServices.COMException e)
        {
            if ((e.ErrorCode & 0xFFFF) == 0xC472)
            {   // Excel is busy
                Thread.Sleep(500); // Wait, and...
                success = false;  // ...try again
            }
            else
            {   // Re-throw!
                throw e;
            }
        }
    }
}

which you could call with lamdas like this:

TryUntilSuccess(() =>
{
    RegisterFilter(); // register this thread for IMessageFilter use
    ppt_app.DoSomething();        
    UnRegisterFilter(); // unregister this thread for IMessageFilter use
};)

The reason for this two-pronged approach is that the IMessageFilter strategy is more efficient than throwing exceptions and will more times than not be able to handle the busy messages coming from the app. However, at other times you will have to handle exceptions so you have to do both...

See here for the IMessageFilter implementation which includes wrappers

Hth!

like image 127
Pat Mustard Avatar answered Sep 19 '22 20:09

Pat Mustard


  1. I haven't tried it but Andrew Whitechapel describes the same approach for Office so I guess it should work: http://blogs.msdn.com/b/andreww/archive/2008/11/19/implementing-imessagefilter-in-an-office-add-in.aspx

  2. Give it a try :)

  3. Another way would be to implement some sort of waiting mechanism by catching the error and retrying (also mentioned here).

like image 21
Paul B. Avatar answered Sep 21 '22 20:09

Paul B.