.net COM 互操作不会将所有 COM 消息直接路由回调用方。如果您从 STA 调用 COM,它将无法理解您的应用程序如何处理重新进入。这意味着可以通过重试处理的失败消息最终会导致异常。
尝试实现IMessageFilter接口。这将允许 COM 了解如何将消息传递回您的应用程序。特别是,实现RetryRejectedCall并检查是否失败标志并可能返回超时值(例如 1000 毫秒)以允许 COM 在短暂暂停后重试。
它是一种 COM 类型,因此这是定义接口所需的代码:
[ComImport, InterfaceType(ComInterfaceType.InterfaceIsIUnknown), Guid("00000016-0000-0000-C000-000000000046")]
public interface IMessageFilter
{
[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);
}
这是一个如何实现它的示例:
public class MyMessageFilter : IMessageFilter
{
int IMessageFilter.HandleInComingCall(int dwCallType, IntPtr hTaskCaller,int dwTickCount, IntPtr lpInterfaceInfo)
{
// 0 means that it's handled.
return 0;
}
int IMessageFilter.RetryRejectedCall(IntPtr hTaskCallee, int dwTickCount, int dwRejectType)
{
// The return value is the delay (in ms) before retrying.
return 1000;
}
int IMessageFilter.MessagePending(IntPtr hTaskCallee, int dwTickCount, int dwPendingType)
{
// 1 hear means that the message is still not processed and to just continue waiting.
return 1;
}
}
实现消息过滤器后,您需要使用CoRegisterMessageFilter注册它。这是按线程注册的,因此请注意您在哪个线程上调用它。PInvoke 签名是:
[DllImport("ole32.dll")]
static extern int CoRegisterMessageFilter(IMessageFilter lpMessageFilter, out IMessageFilter lplpMessageFilter);
即使这不起作用,至少,如果您将所有消息记录在过滤器中,您应该希望获得有关问题所在的更多信息。查看传递到消息过滤器的参数值。如果您查找它们,它们将与错误/状态代码有关。
[请注意,我在这里指的 IMessageFilter 与System.Windows.Forms.IMessageFilter不同,因此请确保您不会意外使用winforms。]