.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 signiture is:
[DllImport("ole32.dll")]
static extern int CoRegisterMessageFilter(IMessageFilter lpMessageFilter, out IMessageFilter lplpMessageFilter);
即使这是不行的,至少是,如果您登录在过滤器中的所有邮件,你应该希望得到关于什么错误一些更多的信息。查看传递给消息过滤器的参数的值。如果你查看它们,它们将涉及错误/状态代码。
[请注意,我在这里提到的IMessageFilter不同于System.Windows.Forms.IMessageFilter,所以请确保您不会意外地使用winforms。]
我很好奇这个新创建的互操作程序集。如果有人能解释为什么这是必要的,我会很感激。控件是否必须托管在某个容器内?是否可以在脚本方案中使用该控件?这个JScript像原始问题中的例子一样失败:WScript.CreateObject(“AcroPDFLib.AcroPDF”) – knut 2010-04-24 13:59:44