如何:修复“应用程序正忙”和“被调用者拒绝了调用”错误
如果以编程方式从外部(进程外)多线程应用程序调入 Visual Studio 自动化,则可能会收到以下错误:
应用程序正忙 (RPC_E_CALL_REJECTED 0x80010001)
被调用者拒绝了调用 (RPC_E_SERVERCALL_RETRYLATER 0x8001010A)
之所以会出现这些错误,是因为外部多线程应用程序与 Visual Studio 之间存在线程争用问题。 通过在 Visual Studio 自动化应用程序中实现 IOleMessageFilter 错误处理程序可以消除这些错误。 (不要将 IOleMessageFilter 与 System.Windows.Forms.IMessageFilter 混淆。)
修复错误
将以下类添加到应用程序中。
添加指向“Microsoft 开发环境 8.0”的 COM 引用。此操作将对 EnvDTE 和 EnvDTE80 的引用添加到解决方案中。
在代码中,创建 EnvDTE80 的实例,如以下示例中所述。
调用 Message.Register 处理线程错误。
按常规方式调用自动化代码。
完成自动化代码后,调用 Message.Revoke 移除线程错误处理程序。
示例
using System;
using System.Collections.Generic;
using System.Text;
using EnvDTE;
using EnvDTE80;
using System.Runtime.InteropServices;
namespace ConsoleApplication2
{
class Program
{
static void Main(string[] args)
{
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.==
// =====================================
// For example, get a reference to the solution2 object
// and do what you like with it.
Solution2 soln = (Solution2)dte.Solution;
System.Windows.Forms.MessageBox.Show
("Solution count: " + soln.Count);
// =====================================
// All done, so shut down the IDE...
dte.Quit();
// and turn off the IOleMessageFilter.
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);
}
}
可靠编程
当外部多线程应用程序调入 Visual Studio 时,它会通过 COM 接口。 COM 有时会有妥善处理线程方面的问题,特别计时方面的问题。 因此,有时无法在传入线程到达时通过 Visual Studio 立即处理从外部应用程序传入的线程,从而导致前面提到的错误。 但是,如果从在 Visual Studio 中(进程内)运行的应用程序(例如,宏或外接程序)调用,则不会出现此情况。 有关此问题背后的原因的更详细说明,请参见 Office 中的线程支持。
若要避免这些错误,请在您的应用程序中实现 IOleMessageFilter 处理程序函数。 实现该处理程序函数后,如果您的外部应用程序线程调入 Visual Studio,然后被拒绝(即它从 IOleMessageFilter.HandleIncomingCall 方法返回 SERVERCALL_RETRYLATER),您的应用程序就可以处理该线程,然后重试或取消调用。 若要执行此操作,请在一个单线程单元 (STA) 中通过 Visual Studio 应用程序启动新线程,并将自动化代码包含在 IOleMessageFilter 处理程序中。