Visual Studio 2017 - 消息过滤器指示应用程序正忙
Visual Studio 2017 - Message filter indicated that the application is busy
我正在移植一个小型控制台应用程序,该应用程序删除磁盘上不在 Visual Studio 项目中的文件。此代码在 Visual Studio 2013 年有效,但我在 Visual Studio 2017 年 运行 时收到以下错误:
System.Runtime.InteropServices.COMException: 'The message filter
indicated that the application is busy. (Exception from 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# class。
- 我尝试只使用 EnvDTE,而不是 EnvDTE80,但收到了同样的错误。
使用 CoRegisterMessageFilter function 注册的 IOleMessageFilter 的实现必须在 STA 单元线程中。
来自 CoRegisterMessageFilter 函数文档:
Only one message filter can be registered for each thread. Threads in
multithreaded apartments cannot have message filters.
您的问题表明您正在通过小型控制台应用程序进行移植,并表明您正在使用 C#。我不知道 porting 到底意味着什么,但是如果原始代码在 VB.Net 中,VB.Net 会自动将控制台应用程序标记为 STAThreadAttribute,其中- 因为 C# 没有,因此线程是在 MTA 线程中创建的。
在 C# 中,您将属性应用于入口方法 (Main
),如下所示。
namespace ConsoleApp1
{
class Program
{
[STAThread]
static void Main(string[] args)
{
}
}
}
所以我遇到了与这个问题类似的问题。我按照接受的答案中的指示添加了 STAThread 属性,但除了获得 RPC_E_SERVERCALL_RETRYLATER
异常外,我还获得了 RPC_E_CALL_REJECTED
异常。经过一番谷歌搜索后,我发现了以下 MS 文档:
上面来自 MS 的文档指出,为了避免这些错误,我们可以实现一个 COM 消息过滤器 (IOleMessageFilter),如果我们收到 RPC_E_CALL_REJECTED
消息,它只是告诉 COM 接口重试,如果我们收到 RPC_E_SERVERCALL_RETRYLATER
留言。
希望这对迷路的人有所帮助。
我正在移植一个小型控制台应用程序,该应用程序删除磁盘上不在 Visual Studio 项目中的文件。此代码在 Visual Studio 2013 年有效,但我在 Visual Studio 2017 年 运行 时收到以下错误:
System.Runtime.InteropServices.COMException: 'The message filter indicated that the application is busy. (Exception from 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# class。
- 我尝试只使用 EnvDTE,而不是 EnvDTE80,但收到了同样的错误。
使用 CoRegisterMessageFilter function 注册的 IOleMessageFilter 的实现必须在 STA 单元线程中。
来自 CoRegisterMessageFilter 函数文档:
Only one message filter can be registered for each thread. Threads in multithreaded apartments cannot have message filters.
您的问题表明您正在通过小型控制台应用程序进行移植,并表明您正在使用 C#。我不知道 porting 到底意味着什么,但是如果原始代码在 VB.Net 中,VB.Net 会自动将控制台应用程序标记为 STAThreadAttribute,其中- 因为 C# 没有,因此线程是在 MTA 线程中创建的。
在 C# 中,您将属性应用于入口方法 (Main
),如下所示。
namespace ConsoleApp1
{
class Program
{
[STAThread]
static void Main(string[] args)
{
}
}
}
所以我遇到了与这个问题类似的问题。我按照接受的答案中的指示添加了 STAThread 属性,但除了获得 RPC_E_SERVERCALL_RETRYLATER
异常外,我还获得了 RPC_E_CALL_REJECTED
异常。经过一番谷歌搜索后,我发现了以下 MS 文档:
上面来自 MS 的文档指出,为了避免这些错误,我们可以实现一个 COM 消息过滤器 (IOleMessageFilter),如果我们收到 RPC_E_CALL_REJECTED
消息,它只是告诉 COM 接口重试,如果我们收到 RPC_E_SERVERCALL_RETRYLATER
留言。
希望这对迷路的人有所帮助。