locked
The message filter indicated that the application is busy. (Exception from HRESULT: 0x8001010A (RPC_E_SERVERCALL_RETRYLATER)) RRS feed

  • Question

  • Hi

    I am trying to develop an application to split power point slides. Application is stable when there all split requests are in queue and catered one by one.  When I try to make it async and tried to run two requests simultaneously I am getting error: The message filter indicated that the application is busy. (Exception from HRESULT: 0x8001010A (RPC_E_SERVERCALL_RETRYLATER))

    COM object does not support multi-threading and there is a workaround provided provided by Microsoft Help Center (Implemented in solution) but it didn't work well.

    How can I achieve parallel processing for single threaded Interop applications.

     Here is sample Code

      static void Main(string[] args)
            {
                MainAsync().GetAwaiter().GetResult();
            }

            static async Task MainAsync()
            {
                try
                {
                    EnvDTE80.DTE2 dte;
                    object obj = null;
                    System.Type t = null;

                    // Get the ProgID for DTE 8.0.
                    t = System.Type.GetTypeFromProgID("VisualStudio.DTE.10.0",
                      true);
                    // Create a new instance of the IDE.
                    obj = System.Activator.CreateInstance(t, true);
                    // Cast the instance to DTE2 and assign to variable dte.
                    dte = (EnvDTE80.DTE2)obj;

                    // Register the IOleMessageFilter to handle any threading 
                    // errors.
                    MessageFilter.Register();
                    // Display the Visual Studio IDE.
                    dte.MainWindow.Activate();

                    // =====================================
                    // ==Insert your automation code here.==
                    // =====================================

                    await SplitSlides(@"PptFile1ToSplit");
                    await SplitSlides(@"PptFile2ToSplit");

                    dte.Quit();

                    MessageFilter.Revoke();

                }
                catch (Exception ex)
                {

                    Console.WriteLine(ex.Message);
                }

                Console.Read();
            }
            private static async Task SplitSlides(string fileName)
            {
                if (!File.Exists(fileName))
                {
                    Console.WriteLine($"File {fileName} does not exist", fileName);
                }

                await Task.Run(() =>
                 {
                     try
                     {
                         // Array with path
                         List<String> SlideFilesTemp = new List<string>();

                         // Copy current file to temporary file
                         string TempFileName = Guid.NewGuid() + ".pptx";
                         string TempFilePath = Path.GetDirectoryName(fileName);
                         string TempFolder = "D:\\Temp";
                         string TempFileNamePathGlob = Path.Combine(TempFolder, TempFileName);
                         File.Copy(fileName, TempFileNamePathGlob);
                         Console.WriteLine("File copied : {0} => {1}", fileName, TempFileNamePathGlob);


                         PpSlideSizeType slideSize = PpSlideSizeType.ppSlideSizeOnScreen;
                         //Count Number of Slides
                         Microsoft.Office.Interop.PowerPoint.Application pptApplication = new Microsoft.Office.Interop.PowerPoint.Application();

                         Presentation pptPresentationTemp = pptApplication.Presentations.Open(
                                           TempFileNamePathGlob,
                                           MsoTriState.msoFalse,
                                           MsoTriState.msoFalse,
                                           MsoTriState.msoFalse);
                         int _slidesCount = pptPresentationTemp.Slides.Count;
                         slideSize = pptPresentationTemp.PageSetup.SlideSize;
                         List<String> SlideNameDest = GetSlideNames(fileName, _slidesCount);
                         pptPresentationTemp.Close();
                         pptApplication.Quit();


                         Console.WriteLine("Count slides in presentation : {0}", _slidesCount);
                         pptApplication = new Microsoft.Office.Interop.PowerPoint.Application();
                         try
                         {


                             for (int j = 1; j <= _slidesCount; j++)
                             {
                                 int k = j - 1;
                                 string slideName = SlideNameDest[k];

                                 string slideFileName = Path.GetFileName(slideName);
                                 string tempSlideFilePath = Path.Combine(TempFolder, slideFileName);

                                 Presentation pptPresentationDest = pptApplication.Presentations.Add(MsoTriState.msoFalse);
                                 pptPresentationDest.PageSetup.SlideSize = slideSize;
                                 pptPresentationDest.Slides.InsertFromFile(TempFileNamePathGlob, 0, j, j);
                                 pptPresentationDest.Slides[1].ApplyTemplate(TempFileNamePathGlob);
                                 pptPresentationDest.SaveAs(tempSlideFilePath, PpSaveAsFileType.ppSaveAsDefault, MsoTriState.msoTrue);
                                 pptPresentationDest.Close();
                                 Console.WriteLine("Done prepare presentation for slide ID : {0}", j);
                                 SlideFilesTemp.Add(tempSlideFilePath);
                             }

                         }
                         catch (Exception)
                         {

                             throw;
                         }
                         finally
                         {
                             if (pptApplication != null)
                                 pptApplication.Quit();
                         }


                         // Copy and remove all created files to S3
                         foreach (string slide in SlideFilesTemp)
                         {
                             string FileName = Path.GetFileName(slide);
                             string CopyPath = Path.Combine(TempFilePath, FileName);
                             File.Copy(slide, CopyPath);
                             Console.WriteLine("File copied : {0} => {1}", slide, CopyPath);

                             File.Delete(slide);
                             Console.WriteLine("File deleted : {0}", slide);
                         }

                         Console.WriteLine("All tasks are done for file {0}", fileName);

                         // Remove temporary file
                         File.Delete(TempFileNamePathGlob);
                         Console.WriteLine("File {0} was removed", TempFileNamePathGlob);
                     }
                     catch (Exception e)
                     {
                         Console.WriteLine($"Failed to split file {fileName}", fileName);
                         //throw;
                     }
                     finally
                     {

                     }
                 });

            }

            private static List<string> GetSlideNames(string fileName, int countOfPages)
            {

                List<string> slideNames = new List<string>();
                foreach (var i in Enumerable.Range(0, countOfPages))
                {
                    var slideName = fileName.Insert(fileName.Length - 5, $"-{i + 1}");
                    slideNames.Add(slideName);
                }
                return slideNames;
            }
        }

        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);
        }

    Thanks

    Monday, October 9, 2017 10:52 AM

All replies

  • Hello,

    You may consider using the Open XML SDK if you deal with open XML documents only. See Welcome to the Open XML SDK 2.5 for Office for more information. 

    The Office object model is not thread safe. In the case of solutions created by using the Office development tools in Visual Studio, COM interop converts all rejected calls to a System.Runtime.InteropServices.COMException ("The message filter indicated that the application is busy"). Whenever you make an object model call on a background thread, you must to be prepared to handle this exception. Typically, that involves retrying for a certain amount of time and then displaying a dialog. However, you can also create the background thread as STA and then register a message filter for that thread to handle this case. Read more about that in the Threading Support in Office article.


    profile for Eugene Astafiev at Stack Overflow, Q&A for professional and enthusiast programmers

    Monday, October 9, 2017 2:27 PM