.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