Josh
Josh

Reputation: 8477

Visual Studio 2017 - Message filter indicated that the application is busy

I'm porting over a small console application that deletes files on disk that are not in a Visual Studio project. This code worked in Visual Studio 2013, but I'm receiving the following error when I ran it in Visual Studio 2017:

System.Runtime.InteropServices.COMException: 'The message filter indicated that the application is busy. (Exception from HRESULT: 0x8001010A (RPC_E_SERVERCALL_RETRYLATER))'

Current Code:

public static int DeleteFilesNotInProject(string solutionFileAndPath, string projectName, string extension)
    {
        var returnValue = 0;
        EnvDTE80.DTE2 dte;

        // Targets Visual Studio 2017
        dte = (EnvDTE80.DTE2)Activator.CreateInstance(Type.GetTypeFromProgID("VisualStudio.DTE.15.0", true), true);

        MessageFilter.Register();

        System.Threading.Thread.Sleep(2000);

        while (!dte.Solution.IsOpen)
        {
            // make sure it is ready to open
            System.Threading.Thread.Sleep(500);
            dte.Solution.Open(solutionFileAndPath);
        }

        dte.Solution.Open(solutionFileAndPath);

        System.Threading.Thread.Sleep(5000);

        foreach (Project project in dte.Solution.Projects)
        {
            if (project.UniqueName.EndsWith(projectName))
                foreach (string s in GetFilesNotInProject(project, extension))
                {
                    FileInfo fi = new FileInfo(s);
                    File.SetAttributes(s, FileAttributes.Normal);
                    File.Delete(s);
                    returnValue++;
                }
        }

        dte.Quit();

        MessageFilter.Revoke();

        return returnValue;
    }

The exception is thrown on the while (!dte.Solution.IsOpen) line. I tried commenting that out and then it is thrown on the foreach (Project project in dte.Solution.Projects) line instead.

Notes:

Upvotes: 1

Views: 3607

Answers (2)

Cabbage Champion
Cabbage Champion

Reputation: 1213

So I had a similar issue to this question. I added the STAThread attribute as directed in the accepted answer but in addition to getting the RPC_E_SERVERCALL_RETRYLATER exception, I also got the RPC_E_CALL_REJECTED exception as well. After some googling I came across the following MS document:

https://learn.microsoft.com/en-us/previous-versions/visualstudio/visual-studio-2010/ms228772(v=vs.100)?redirectedfrom=MSDN

The above doc from MS states that to avoid these errors we can implement a COM message filter (IOleMessageFilter) that simply tells the COM interface to retry if we get the RPC_E_CALL_REJECTED message and wait if we get RPC_E_SERVERCALL_RETRYLATER message.

Hope this helps someone who is lost.

Upvotes: 1

TnTinMn
TnTinMn

Reputation: 11801

The implementation of the IOleMessageFilter registered using the CoRegisterMessageFilter function must be in a STA apartment thread.

From the CoRegisterMessageFilter function documentation:

Only one message filter can be registered for each thread. Threads in multithreaded apartments cannot have message filters.

Your question stated that you are porting over a small console application and indicates that you are using C#. I don't know exactly what porting implies, but if the original code was in VB.Net, VB.Net automatically marks Console applications with the STAThreadAttribute where-as C# does not and as such the thread is created in a MTA thread.

In C#, you apply the attribute to the entry method (Main) as shown below.

namespace ConsoleApp1
{
    class Program
    {
        [STAThread]
        static void Main(string[] args)
        {
        }
    }
}

Upvotes: 7

Related Questions