winforms - 是什么导致 InvalidComObjectException : "COM object that has been separated from its underlying RCW cannot be used."?

标签 winforms interop activex dispose finalizer

我查看了提到这个特定异常的各种问题(我访问过的 this question lists many of them)。另外,我有同样的general question as this post ,但在不同的上下文中,所以 the answer对我没有帮助。
上下文
我有一个派生自 AxWindowsMediaPlayer 的类属于一个名为 View 的类,在 Panel 内,在 Workspace 内.我最近问 a question围绕这种情况,但该问题是针对我解​​决此问题的方法是否可行。该问题的背景与此处相关:
.------------------------。
|工作空间 |
|.--------. .--------。 |
||面板1 | |面板2 | |
||.-----。 | |.-----。 | |
|||查看1| | ||查看2| | |
||'-----' | |'-----' | |
|'--------' '--------' |
'------------'

当一个 View被处置,一个名为 Synchronize() 的方法将调用所有剩余的 View对象。对于View包含 AxWindowsMediaPlayer , 它调用 videoPlayer.Error.clearErrorQueue() .
问题
当我调用 Dispose()在顶层 ( Workspace.Dispose() ),如果另一个 View被处置,然后导致 Synchronize()在剩余的 View 上调用对象,View包含 AxWindowsMediaPlayer类在 videoPlayer.Error.clearErrorQueue() 上引发异常行,说明:

InvalidComObjectException: COM object that has been separated from its underlying RCW cannot be used.


我对 AxWindowsMediaPlayer 的方式感到困惑。正在与其底层 RCW ( Runtime Callable Wrapper ) 分离。我已阅读 this article that talks about this exception以及调用 Marshal.ReleaseComObject() 的危险.我没有明确地调用这个方法。我在 Dispose 设置了断点Panel的方法和 ViewVideoPlayerControl (派生自 AxWindowsMediaPlayer )类,但在异常发生之前没有一个会受到影响。
我的解决方法是确保 View媒体播放器总是首先得到处理。这是我上一个问题背后的动机。但我想了解这是如何发生的,所以我可以看看这是否是我需要解决的问题。 谁造成了AxWindowsMediaPlayerDispose 之前与其 RCW 分离在父类上被调用?
我的猜测是 AxWindowsMediaPlayer GC 调用了终结器,但我不明白是什么触发了它。出于某种原因,请调用 Dispose在更高级别导致Marshal.ReleaseComObject在地板下被召唤。有人可以启发我吗?

最佳答案

不幸的是,您的解决方法是解决方案。
Control.Dispose首先递归处理所有 ActiveX 控件,然后递归调用 Dispose在子控件上。在您的示例中,如果您调用 Workspace.Dispose , 你的 AxWindowsMediaPlayer将首先处理,然后 Panel1 , Panel2 , View1 , View2 (取决于您建立控制树的顺序)。

我们可以通过 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 控件,但这不是事情的实现方式。

关于winforms - 是什么导致 InvalidComObjectException : "COM object that has been separated from its underlying RCW cannot be used."?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5302949/

相关文章:

c# - 通过 ListView 进行 foreach 并访问子项?

c# - 从 C# 访问 Win32 C/C++ 结构成员

silverlight - Silverlight 可以包含 ActiveX 吗?

c# - 使控件及其字体更大

winforms - 我应该恢复 Clippy 吗? aka 我如何在桌面应用程序中提供用户友好的提示和帮助?

c# - 为什么 Mono 中的 Winforms 没有打开任何窗口?

c# - PresentationSource.FromVisual(this) 在 WPF 中返回空值

c++ - 如何正确地将 u8 字符串文字传递给接受 UTF-8 字符串的 C 函数

javascript - 查找 ActiveX COM 组件的版本

javascript - 使用javascript扫描目录