5

この特定の例外に言及しているさまざまな質問を見てきました(この質問には、私が訪れたそれらの多くがリストされています)。また、この投稿と同じ一般的な質問がありますが、文脈が異なるため、回答は役に立ちません。

コンテキスト

から派生したクラスがあり、AxWindowsMediaPlayerというクラスによって所有されています。Viewこれは 内にありPanel、 内にありWorkspaceます。最近、この状況について質問しましたが、その質問は、この問題に対する私の回避策が大丈夫かどうかに向けられたものでした。その質問の背景は、ここで関連しています。

    -----------------------。
    |ワークスペース |
    |.--------. .--------. | |
    ||パネル1 | |パネル2 | | |
    ||.-----. | | |.-----. | | | |
    |||ビュー1| | | ||View2| | | | |
    ||'-----' || |'-----' | | |
    |'--------' '--------' |
    「----------------------」

が破棄されると、呼び出されViewたメソッドSynchronize()が残りのすべてのViewオブジェクトで呼び出されます。Viewを含むに対して、をAxWindowsMediaPlayer呼び出しますvideoPlayer.Error.clearErrorQueue()

問題

Dispose()トップ レベル ( Workspace.Dispose()) で呼び出したときに、別のオブジェクトViewが破棄さSynchronize()れ、残りのViewオブジェクトで呼び出されると、Viewそのクラスを含むAxWindowsMediaPlayerクラスがその行で例外をスローし、次のvideoPlayer.Error.clearErrorQueue()ように述べます。

InvalidComObjectException: 基になる RCW から分離された COM オブジェクトは使用できません。

が基礎となる RCW ( Runtime Callable WrapperAxWindowsMediaPlayer )からどのように分離されているのか、私は戸惑っています。この例外と呼び出しの危険性について説明しているこの記事を読みました。このメソッドを明示的に呼び出しているわけではありません。andおよび(から派生) クラスのメソッドにブレークポイントを配置しましたが、例外が発生する前にそれらのいずれにもヒットしません。Marshal.ReleaseComObject()DisposePanelViewVideoPlayerControlAxWindowsMediaPlayer

私の回避策はView、メディア プレーヤーの が常に最初に破棄されるようにすることです。これが前回の質問の動機でした。しかし、これがどのように起こっているのかを理解したいので、これを修正する必要があるかどうかを確認できます. 親クラスで呼び出される前に、誰がAxWindowsMediaPlayerRCW から分離させているのでしょうか?Dispose

私の推測では、AxWindowsMediaPlayerファイナライザーが GC によって呼び出されていると思いますが、何がそれを引き起こしているのかわかりません。Disposeどういうわけか、より高いレベルで呼び出すMarshal.ReleaseComObjectと、床下で呼び出されるようになります。誰かが私を啓発できますか?

4

1 に答える 1

3

残念ながら、あなたの回避策が解決策です。

Control.Dispose最初にすべての ActiveX コントロールを再帰的に破棄し、次に子コントロールを再帰的に呼び出しDisposeます。あなたの例では、 を呼び出すとWorkspace.DisposeAxWindowsMediaPlayer最初に破棄され、次にPanel1Panel2View1View2破棄されます (コントロール ツリーを構築した順序によって異なります)。

Reflectorを使用して原因を発見できます。を調べてみるControl.Disposeと、基本的に次のように実装されています (注意: 無関係なコードは省略され、読みやすくするためにわずかに変更されています)。

protected override void Dispose(bool disposing)
{
    if (disposing)
    {
        DisposeAxControls();

        foreach (Control control in Controls)
        {
            control.Parent = null;
            control.Dispose();
        }

        base.Dispose(disposing);
    }
}

そしてDisposeAxControls、次のように実装されています。

internal virtual void DisposeAxControls()
{
    foreach (Control control in Controls)
    {
        control.DisposeAxControls();
    }
}

このクラスは、ホストされている ActiveX コントロールを破棄するためにAxHostオーバーライドします。DisposeAxControls

DisposeAxControls関数が存在する理由がよくわかりません。他のみんなと同じように、AxHost単純に をオーバーライドして ActiveX コントロールを破壊したように見えますが、実装方法はそうではありません。Dispose

于 2011-04-06T23:09:18.997 に答える