.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 のものを使用しないように注意してください。]