7

コードで の新しいインスタンスを作成しようとするとMicrosoft.Office.Interop.PowerPoint.Application、次の例外が発生することがあります。

System.Runtime.InteropServices.COMException (0x80010001): Retrieving the COM class factory for component with CLSID {91493441-5A91-11CF-8700-00AA0060263B} failed due to the following error: 80010001 Call was rejected by callee. (Exception from HRESULT: 0x80010001 (RPC_E_CALL_REJECTED)).
   at System.Runtime.Remoting.RemotingServices.AllocateUninitializedObject(RuntimeType objectType)
   at System.Runtime.Remoting.Activation.ActivationServices.CreateInstance(RuntimeType serverType)
   at System.Runtime.Remoting.Activation.ActivationServices.IsCurrentContextOK(RuntimeType serverType, Object[] props, Boolean bNewObj)
   at System.RuntimeTypeHandle.CreateInstance(RuntimeType type, Boolean publicOnly, Boolean noCheck, Boolean& canBeCached, RuntimeMethodHandleInternal& ctor, Boolean& bNeedSecurityCheck)
   at System.RuntimeType.CreateInstanceSlow(Boolean publicOnly, Boolean skipCheckThis, Boolean fillCache)
   at System.RuntimeType.CreateInstanceDefaultCtor(Boolean publicOnly, Boolean skipVisibilityChecks, Boolean skipCheckThis, Boolean fillCache)
   at System.Activator.CreateInstance(Type type, Boolean nonPublic)

同じ入力が与えられても一貫して発生しないため、時々言います。さらに、PowerPoint オートメーション API とやり取りするコードの他の部分でも (同じように一貫性を欠いて) 発生します。

MSDN 自体からこのソリューションを試してみましたが、これは最も推奨されるソリューションと思われます。ただし、同じ動作を引き続き観察しているため、影響はないようです。

私の質問は次のとおりです。

  1. MSDN ソリューションは PowerPoint オートメーションで機能しますか?
  2. コードに正しく適用されているかどうかを確認するにはどうすればよいですか?
  3. 誰かが代替ソリューションを持っていますか?

C#、.NET 4、および PowerPoint 2007 を使用しています。

4

2 に答える 2

4

私は以前にこれに出くわしたことがあり、ポール Bは確かに正しいです。これは、Powerpoint OM をメイン スレッド (つまりThis_AddIn) から呼び出しているかどうかによって異なります。そうであれば、ppt はこれらの例外をスローすべきではありません。ただし、別のスレッドから ppt を呼び出している場合は、IMessageFilterこれらの Windows メッセージ ポンプ エラーを効率的に処理するように実装する必要があります。これは、ppt が他のスレッドからの呼び出しよりも OM へのメイン スレッド呼び出しを優先するため、呼び出しが拒否されるためです。

. _ COMException_ ここ0x800AC472 (VBA_E_IGNORE)に例があります。

したがって、完全な解決策は、スローされる可能性のある他のタイプの OM 呼び出しを処理するために、OM 呼び出しをラップするsepp2k のIMessageFilterコードのようなものを実装して使用することです。COMException

したがって、彼のようなコードをラップするには:

private void TryUntilSuccess(Action action)
{
    bool success = false;
    while (!success)
    {
        try
        {
            action();
            success = true;
        }

        catch (System.Runtime.InteropServices.COMException e)
        {
            if ((e.ErrorCode & 0xFFFF) == 0xC472)
            {   // Excel is busy
                Thread.Sleep(500); // Wait, and...
                success = false;  // ...try again
            }
            else
            {   // Re-throw!
                throw e;
            }
        }
    }
}

次のようにラムダで呼び出すことができます:

TryUntilSuccess(() =>
{
    RegisterFilter(); // register this thread for IMessageFilter use
    ppt_app.DoSomething();        
    UnRegisterFilter(); // unregister this thread for IMessageFilter use
};)

この 2 つのアプローチの理由は、IMessageFilter戦略が例外をスローするよりも効率的であり、アプリからのビジー メッセージを処理できない回数よりも多いためです。ただし、例外を処理する必要がある場合もあるため、両方を行う必要があります...

ラッパーを含むIMessageFilter 実装については、こちらを参照してください

ちょ!

于 2015-10-16T06:03:24.347 に答える
3
  1. 私は試していませんが、Andrew Whitechapel が Office について同じアプローチを説明しているので、うまくいくはずです: http://blogs.msdn.com/b/andreww/archive/2008/11/19/implementing-imessagefilter-in- an-office-add-in.aspx

  2. 試してみる :)

  3. 別の方法は、エラーをキャッチして再試行することにより、ある種の待機メカニズムを実装することです (こちらでも説明されています)。

于 2012-09-11T08:43:37.627 に答える