Visual Studio 2017 - 消息过滤器指示应用程序正忙

时间:2018-05-11 22:53:30

标签: c# .net visual-studio visual-studio-2017 envdte

我移植一个小型控制台应用程序,删除磁盘上不在Visual Studio项目中的文件。此代码在Visual Studio 2013中有效,但我在Visual Studio 2017中运行时收到以下错误:

  

System.Runtime.InteropServices.COMException:'邮件过滤器   表示应用程序正忙。 (HRESULT的例外情况:   0x8001010A(RPC_E_SERVERCALL_RETRYLATER))'

当前代码:

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

while (!dte.Solution.IsOpen)行引发异常。我尝试对其进行评论,然后将其放在foreach (Project project in dte.Solution.Projects)行上。

注意:

  • 代码基于此MSDN article。我希望将其保留在控制台应用程序中。
  • 我找到了PowerShell和VS Addons / Extensions,但是我有兴趣将这个C#类称为使用控制台应用程序。
  • 我尝试使用EnvDTE而不是EnvDTE80,但收到了同样的错误。

1 个答案:

答案 0 :(得分:5)

使用CoRegisterMessageFilter function注册的IOleMessageFilter的实现必须位于STA公寓线程中。

来自CoRegisterMessageFilter功能文档:

  

每个线程只能注册一个消息过滤器。线程在   多线程公寓不能有消息过滤器。

您的问题表明您正在移植一个小型控制台应用程序,并表示您正在使用C#。我不确切知道移植意味着什么,但如果原始代码在VB.Net中,VB.Net会自动将控制台应用程序标记为STAThreadAttribute,而C#不会因此,线程是在MTA线程中创建的。

在C#中,您将属性应用于输入方法(Main),如下所示。

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