【问题标题】:What causes the InvalidComObjectException: "COM object that has been separated from its underlying RCW cannot be used."?是什么导致 InvalidComObjectException:“无法使用已与其底层 RCW 分离的 COM 对象。”?
【发布时间】:2011-07-15 05:57:28
【问题描述】:

我查看了提到这个特定异常的各种问题(this question lists many of them,我访问过)。另外,我有相同的general question as this post,但在不同的上下文中,所以the answer 对我没有帮助。

上下文

我有一个派生自AxWindowsMediaPlayer 的类,该类由一个名为View 的类拥有,该类位于Panel 中,位于Workspace 中。我最近就这种情况询问了a question,但这个问题是针对我的 this 问题的解决方法是否可行。该问题的背景与此处相关:

.------------------------。 |工作空间 | |.--------. .--------。 | ||面板1 | |面板2 | | ||.-----。 | |.-----。 | | |||查看1| | ||查看2| | | ||'-----' | |'-----' | | |'--------' '--------' | '------------'

当一个View 被释放时,一个名为Synchronize() 的方法将在所有剩余的View 对象上被调用。对于包含AxWindowsMediaPlayerView,它调用videoPlayer.Error.clearErrorQueue()

问题

当我在顶层 (Workspace.Dispose()) 调用 Dispose() 时,如果另一个 View 被释放,然后导致 Synchronize() 在剩余的 View 对象上被调用,则包含 @ 的 View 987654346@ 类在videoPlayer.Error.clearErrorQueue() 行抛出异常,说明:

InvalidComObjectException:无法使用已与其底层 RCW 分离的 COM 对象。

我对@9​​87654348@ 是如何与其底层 RCW (Runtime Callable Wrapper) 分离感到困惑。我读过this article that talks about this exception 和打电话给Marshal.ReleaseComObject() 的危险。我没有明确地调用这个方法。我在PanelViewVideoPlayerControl(派生自AxWindowsMediaPlayer)类的Dispose 方法上设置了断点,但是在异常发生之前这些都没有被命中。

我的解决方法是确保始终首先处理带有媒体播放器的View。这是我上一个问题背后的动机。但我想了解这是如何发生的,所以我可以看看这是否是我需要解决的问题。 谁在 Dispose 被父类调用之前导致 AxWindowsMediaPlayer 与其 RCW 分离?

我的猜测是 AxWindowsMediaPlayer 终结器被 GC 调用,但我不明白是什么触发了它。出于某种原因,在更高级别调用Dispose 会导致Marshal.ReleaseComObject 在地板下被调用。有人可以启发我吗?

【问题讨论】:

    标签: winforms interop activex dispose finalizer


    【解决方案1】:

    不幸的是,您的解决方法就是解决方案。

    Control.Dispose 首先递归处理所有 ActiveX 控件,然后递归调用子控件上的 Dispose。在您的示例中,如果您调用Workspace.Dispose,您的AxWindowsMediaPlayer 将首先被处理,然后是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();
        }
    }
    

    AxHost 类覆盖 DisposeAxControls 以销毁托管的 ActiveX 控件。

    我不太确定DisposeAxControls 函数为何存在。似乎AxHost 会像其他人一样简单地覆盖Dispose 来破坏 ActiveX 控件,但事情不是这样实现的。

    【讨论】:

      猜你喜欢
      • 2011-07-03
      • 2011-11-21
      • 2012-04-27
      • 1970-01-01
      • 1970-01-01
      • 2022-08-09
      • 1970-01-01
      • 1970-01-01
      • 2012-09-17
      相关资源
      最近更新 更多