Office Interop and Call was rejected by callee

28. September 2012 13:14 by Mrojas in ActiveX, C#, Memory, VB6 Migration, WinForms  //  Tags: , ,   //   Comments (0)

This issue is mostly cause by timing issues when calling a multi-threaded app.

Some workarounds:

 

1. Set the application visible property to false. For example if using Word make word visible property false at the start of the method and set it back to true at the end.

This will delay some GUI changes avoiding timing issues.

 

2. Insert some Thread.Sleep calls (yes this is ugly)

 

3. Register and IOleMessageFilter. I have copied an implementation from the MSDN

 

Just copy this class in your code.

At the start of the method call 

 

            MessageFilter.Register();
            // This registers the IOleMessageFilter to handle any threading 
            // errors.

 

And at the end

MessageFilter.Revoke();

public class MessageFilter : IOleMessageFilter
{

        //
        // Class containing the IOleMessageFilter
        // thread error-handling functions.

        // Start the filter.
        public static void Register()
        {
            IOleMessageFilter newFilter = new MessageFilter(); 
            IOleMessageFilter oldFilter = null; 
            CoRegisterMessageFilter(newFilter, out oldFilter);
        }


        // Done with the filter, close it.
        public static void Revoke()
        {
            IOleMessageFilter oldFilter = null; 
            CoRegisterMessageFilter(null, out oldFilter);
        }


        //
        // IOleMessageFilter functions.
        // Handle incoming thread requests.
        int IOleMessageFilter.HandleInComingCall(int dwCallType, 
        System.IntPtr hTaskCaller, int dwTickCount, System.IntPtr lpInterfaceInfo) 
        {

            //Return the flag SERVERCALL_ISHANDLED.
            return 0;
        }


        // Thread call was rejected, so try again.
        int IOleMessageFilter.RetryRejectedCall(System.IntPtr 
        hTaskCallee, int dwTickCount, int dwRejectType)
        {

            if (dwRejectType == 2)
            // flag = SERVERCALL_RETRYLATER.
            {
                // Retry the thread call immediately if return >=0 & 
                // <100.
                return 99;
            }
            // Too busy; cancel call.
            return -1;
        }


        int IOleMessageFilter.MessagePending(System.IntPtr hTaskCallee, 
        int dwTickCount, int dwPendingType)
        {
            //Return the flag PENDINGMSG_WAITDEFPROCESS.
            return 2; 
        }


        // Implement the IOleMessageFilter interface.
        [DllImport("Ole32.dll")]
        private static extern int 
          CoRegisterMessageFilter(IOleMessageFilter newFilter, out 
          IOleMessageFilter oldFilter);
    }



    [ComImport(), Guid("00000016-0000-0000-C000-000000000046"), 
    InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIUnknown)]
    interface IOleMessageFilter 
    {
        [PreserveSig]
        int HandleInComingCall( 
        int dwCallType, 
        IntPtr hTaskCaller, 
        int dwTickCount, 
        IntPtr lpInterfaceInfo);

        [PreserveSig]
        int RetryRejectedCall( 
        IntPtr hTaskCallee, 
        int dwTickCount,
        int dwRejectType);


        [PreserveSig]
        int MessagePending( 
            IntPtr hTaskCallee, 
            int dwTickCount,
            int dwPendingType);
    }